Table of Contents

  • Introduction

  • Part 1. Desktop

  • Ch1. HTML5 and its New APIs

  • Ch2. Advanced Intro to JavaScript (draft’s ready, not edited)

  • Ch3. Mocking Up Save Sick Child (draft’s ready, not edited)

  • Ch4. Using Ajax and JSON (draft’s ready, not edited)

  • Ch5. Test-Driven Development with JavaScript

  • Ch6. "Save Sick Child with JQuery framework

  • Ch7. "Save a Child" with Ext JS framework

  • Ch8. Large Scale JavaScript Project

  • Ch9. Replacing HTTP with WebSockets (draft’s ready, not edited)

  • Ch10. Securing Web Applications s

  • Part 2. Mobile

  • Ch11. Responsive Design: One Site Fits All (work in progress)

  • Ch12. «Save a Child» With JQuery Mobile

  • Ch13. «Save a Child» with Sencha Touch

  • Ch14. Hybrid Applications: HTML + Native API

Introduction

This is a home of the upcoming book «Enterprise Web Development. From Desktop to Mobile». The authors of this book are Yakov Fain, Victor Rasputnis, Viktor Gamov, and Anatole Tartakovsky. They all work for Farata Systems.

This book will be printed in the Summer of 2013, but you can enjoy read the current manuscript enterprisewebbook.com. The sources of this book are located at Github.

The book is released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported license meaning you can both get a copy of the book for free or help to further improve it. This book will be printed and available for purchase via O’Reilly Media. Readers will have an option of purchasing this book in a number of digital formats.

What’s an Enterprise Web Application?

This book has the word Enterprise in its title, which needs to be explained, and we’ll do it by examples. Creating a Web application that will process orders is not the same as creating a Web site to publish blogs. Enterprise applications include company-specific workflows, and usually they need to be integrated with number of internal systems, data sources and processes.

Google Doc is not an enterprise Web application. But Google appliance integrating search operating on company documents, databases, processes, tickets, and providing collaboration is - it integrates consumer-workforce front office with what the company does (back office).

Google Maps is not an enterprise application. But Google Maps integrated with the company site used by insurance agents to plan daily route, scheduling, doing address verification and geo-coding is.

Just using a Web application in some business doesn’t make it an enterprise Web application. If you take Gmail as is, it won’t be an enterprise application until you integrate it into another process of your business.

Is an online game an enterprise application? It depends on the game. A multi-player online roulette game hooked up to a payment system, and maintaining users' accounts is an enterprise Web application. But playing Sudoku online doesn’t feel too enterprisey.

How about a dating Web site? If the site just offers an ability to display singles - it’s just a publishing site as there is not much of a business there. Can you turn a dating Web site into an enterprise application? It’s possible.

Some people will argue that an enterprise application must supports multiple users, high data load, be scalable, have business and persistence layers, offer professional support et al. We don’t believe that a Web application should do all this to qualify for the adjective enterprise.

Let’s create a simple definition of an enterprise Web application:

"An enterprise Web application is the one that helps an organization running its business online"

In this book we are going to build a Save the Child Web application that will allow people to register, donate, find local kids that need help, match donors and recipients, upload images, videos and display statistics. Would these feature make Save the Child an enterprise Web application? Yes, our non-for-profit organization that collects donations for ill kids is our enterprise.

During the last decade the authors of this book worked on many enterprise Web applications using variety of programming languages and frameworks: HTML, JavaScript, Java, and Flex to name a few. Apache Flex and Java produce compiled code that runs in a well known and predictable virtual machine (JVM and Flash Player respectively).

This book is about developing software using what’s known as HTML5 stack. But only the first chapter of this book will offer you an overview of the selected HTML5 tags and APIs. The second chapter is an advanced introduction to JavaScript. The rest of the chapters are about designing, re-designing, developing, and re-developing a sample Web site Save Sick Child. You’ll be learning whatever is required for building this Web application on the go.

You’ll be using dynamic HTML (DHTML), which is HTML5, JavaScript, and Cascading Style Sheets (CSS). We’ll add to the mix the XMLHttpRequest object that lives in a Web browser and communicates with the server without the need to refresh the entire Web page (a.k.a. AJAX). JSON will be our data format of choice for data exchange between the Web browser and the server.

Warning It’s not possible to provide the detailed coverage of all programming languages, frameworks and tools used in this rather short book. You’ll need to do some additional reading with more in-depth coverage of certain topics. This book is for practitioner who need to learn while developing a project.

From DHTML to HTML5

DHTML has been introduced in Microsoft Internet Explorer (IE) 5, and several years later it was substituted with a more popular acronym AJAX. Back in 1999 Microsoft introduced XMLHttpRequest object to allow the Web version of their mail client Outlook to update the browser’s window without the need to refresh the entire Web page. The market share of IE5 was about 90% at the time, and in enterprises it was literally the only approved browser.

Many years passed by and today’s Internet ecosystems changed quite a bit. Web browsers are a lot smarter and performance of JavaScript improved substantially. The browsers support 6-8-12 simultaneous connections per domain (as opposed to 2 five years ago), which gave a performance boost to all AJAX applications. At least one third of all Web requests is being made from smart phones or tablets. Apple Inc. started their war against browser’s plugins hence using embedded Java VM or Flash Player is not an option there. The growing need to support a huge variety of mobile devices gave another boost for HTML5 stack, which is supported by all devices.

But choosing HTML5 as the least common denominator that works in various devices and browsers means lowering requirements for your enterprise project. From the very beginning parameters like reliability, ability to adapt to different the screen sizes and densities will be simplified comparing to developing for one specific VM, device or OS. Instead of implementing these features, the functional specification will include testing under several Web browsers, in many different screen sizes and resolutions. HTML5 developers spend a lot more time in the debugger that people who develop for a known VM. Get ready to solving problems like a dropdown does not show any data in one browser while working fine in all others. Can you imagine a situation when the click event is not always generated while working in Java, Flex, or Silverlight? Get ready for such surprises while testing your DHTML application.

You’ll save some time because there is no need to compile JavaScript, but you’ll spend more time testing deployed code. The final deliverable of an HTML5 project may have as low as half of the functionality comparing to the same project developed for a VM. But you’ll gain a little better Web adaptability, easier implementation of full text search and mashups. The integration with other technologies will also become easier with HTML/JavaScript. If all these advantages are important to your application choose HTML5.

JavaScript will enforce its limitations on any serious and complex enterprise project. You can develop a number of fairly independent windows, but creating a well tested and reliable HTML5 takes time.

In this book we’ll be using some JavaScript frameworks - the are dozens of those on the market. Several of them promise to cover all the needs of your Web application. Overall, there are two main categories of frameworks:

a) Those that allow you to take an existing DHTML Web site and easily add new attributes to all or some page elements so they would start shining, blinking, or do some other fun stuff. Such frameworks don’t promote component-based development. They may not include navigation components, grids, trees, which are pretty typical for any UI of the corporate tasks. JQuery is probably the best representative of this group- it’s light (30Kb), extendable, and easy to learn.

b) Another group of frameworks offers rich libraries of high-level components and allow you to extend them.But overall, such components are supposed to be used together becoming a platform for your Web UI. These components process some events, offer support of the Model-View-Controller paradigm, have a proprietary way of laying out elements on the Web page, organize navigation et al. Ext JS from Sencha belongs to this group.

We’ll use both JQuery and Ext JS and will show you how to develop Web applications with each of these popular frameworks. JQuery is good for improving an existing JavaScript site. JQuery can be used to program about 80% of a Web site. You should use it for the look and feel support, which is what it’s meant for. But you can’t use it for building your application component model. The component model of Ext JS is applicable in about 20% of a Web site, which includes an application piece rather than just being a set of Web pages. Typically it’s a serious view navigator or a wizard to implement a serious business process or a workflow that includes a client’s part.

JavaScript frameworks are hiding from software developers all incompatibilities and take care of the cases when a Web browser doesn’t support some HTML5, CSS3, or JavaScript features yet.

High-level UI components and a workflow support are needed for a typical enterprise application where the user needs to perform several steps to complete the business process. And these 20% of an application’s code will require 80% of the project time of complex development. So choosing a framework is not the most difficult task. The main problem with DHTML projects is not how to pick the best JavaScript framework for development, but finding the right software developers. Lack of qualified developers increases the importance of using specialized frameworks for code testing. The entire code base must be thoroughly tested over and over again. We’ll discuss this subject in the Chapter 5 dedicated to test-driven development.

A JavaScript developer has to remember all unfinished pieces of code. Many things that we take for granted with compiled languages simply don’t exist in JavaScript. For example, in Java or C# just by looking at the method signature you know what are the data types of the method’s parameters. In JavaScript you can only guess if the parameter names are self descriptive. Take the Google’s framework GWT that allows developers write code in Java with auto-generation of the JavaScript code. Writing code in one language with further conversion and deployment in another one is a controversial idea unless the source and generated languages are very similar. We’re not big fans of GWT, because after writing the code you’ll need to be able to debug it. This is when a Java developer meets a foreign language JavaScript.The ideology and psychology of programming in JavaScript and Java are different. A person who writes in Java/GWT has to know how to read and interpret deployed JavaScript code. On the other hand, using TypeScript or CoffeeScript to produce JavaScript code can be a time saver.

The Ext JS framework creators decided to extend JavaScript introducing their version of classes and more familiar syntax for object-oriented languages. Technically they are extending or replacing the constructs of the JavaScript itself extending the alphabet. Ext JS recommends creating objects using ext.create instead of the operator new. But Ext JS is still a JavaScript framework.

JQuery framework substantially simplifies working with browser’s DOM elements and there are millions of small components that know how to do one thing well, for example, an image slider. But it’s still JavaScript and requires developers to understand the power of JavaScript functions, callbacks, and closures.

Should we develop in HTML5 if its standard is not finalized yet?

The short answer is yes. If you are planning to develop mainly for the mobile market, it’s well equipped with the latest Web browsers and if you’ll run into issues there. they won’t be caused by the lack of HTML5 support. In the market of the enterprise Web applications, the aging Internet Explorer 8 is still being widely used and they don’t support some of the HTML5 specific features. But it’s not a show stopper either.If you are using one of the JavaScript frameworks that offers cross-browser compatibility, most likely, they take care of IE8 issues.

The more conservative approach to achieving the browser compatibility is not by relying on the framework promises, but by testing and adjusting your application in different browsers. The chances are that you may need to be fixing the framework’s code here and there. Maintaining compatibility is a huge challenge for any framework’s vendor, which in some cases can consist of just one developer. You shouldn’t have hard feelings against the developers behind the framework of your choice. These guys simply don’t have time to fix everything. You need to form an attitude that a JavaScript framework is similar to a good Legos set that will require your creativity too. Don’t get angry. Cure the framework. Spend some time working on the framework, and then work on your application code. Ideally, submit your fixes back to the framework’s code base - most of them are open source.

If you are planning to write pure JavaScript, add a tiny framework Modernizr to your code base, which will detect if a certain feature is supported by the user’s Web browser, and if not - provide an alternative solution. We like the analogy with TV sets. People with latest 3D HD TV sets and those who have 50-year old black and white televisions can watch the same movie even though the quality of the picture will be drastically different.

Summary

If you are starting working on your first HTML5 enterprise project, get ready to solve the same tasks as Java, JavaFX, Silverlight, or Flexdevelopers face:

  • Reliability of the network communications. What if the data never arrive from/to the server? Is it possible to recover the lost data? Where they got lost? Can we re-send the lost data? What to do with duplicates?

  • Modularization of your application. If your application has certain rarely used menus don’t even load the code that handles this menu.

  • Perceived performance. How quickly the main window of your application is loaded to the user’s computer? How heavy is the framework’s code base?

  • Should you store the application state on the server or on the client?

  • Does the framework offer a rich library of components?

  • Does the framework support creation of loosely coupled application components? Is the event model well designed?

  • Does the framework of your choice cover most of the needs of your application, or you’ll need to use several frameworks?

  • Is well written documentation available?

  • Does the framework of your choice locks you in? Does it restrict your choices? Can you easily replace this framework with another one if need be?

  • Is there an active community to ask for help with technical questions?

We could continue adding items to this list. But our main message is that developing HTML5 applications is not just about adding tag video and canvas to a Web page. It’s about serious JavaScript programming.

Part 1: Desktop

HTML5 and its New APIs

This is the first and only chapter in this book that’s dedicated to HTML5. You’ll get familiar with some new HTML tags that were introduced to make the markup more semantic and convenient. We’ll also provide a brief overview of selected APIs that are included in HTML5 spec (Web Storage, WebSQL, Web Sockets, and Web Workers).

The majority of the modern Web browsers already support the current version of HTML5 specification. The question is if the users of your Web application have or rather can have a modern browser installed on their device? There are two groups of users that will stick to the outdated browsers for some time:

  1. Computer illiterate people who are afraid of installing any new software one their PCs. Especially, people of the older generation. "John, after the last visit of our grandson our computer works even slower than before. Please don’t let him install these new fancy browsers here. I just need my old Internet Explorer, access to Hotmail and Facebook".

  2. Business users working for large corporations, where all the installations of the software on their PCs is done by professional system administrators. They say, "We have 50000 PCs in or firm. An upgrade from Internet Explorer version 8 to version 9 is a major undertaking. Internal users work with about a hundred Web applications on a regular basis. They can install whatever browser they want, but if some of these application won’t work as expected, the users will flood us with support requests we’re not qualified to resolve . Hence the strategy of using the lowest denominator browser often wins.

In the worst case scenario, Web developers need to make both of these groups happy. Take an online banking - this old couple has to be able to use your Web application from their old PCs otherwise they can transfer their lifetime savings to a different bank which doesn’t require the later version of Firefox for online banking.

Does it mean that enterprise Web developers shouldn’t even bother using HTML5 that’s not 100% supported? Not at all. This means that a substantial portion of their application’s code will be will be bloated by the if-statements figuring out what this specific Web browser supports and providing several solutions that keep your application on float in any Web browser. This what makes the job of DHTML developers a lot more difficult than of, say Java developers who know exactly the environment where their code will work. Of you don’t install the JavaRuntime of version 1.6 our application won’t work. As simple as that. How about asking Java developers writing applications that will work in any runtime released during the last 10 years? No, we’re not that nasty.

Do you believe it would be a good idea for Amazon or Facebook to re-write their UI in Java? Of course not unless they want to loose half of their customers who will be scared to death after seeing the message of the 20-step Java installer asking for the access to the internals of their computer. Each author of this book is a Java developer, and we love using Java… on the server side. But when it comes to the consumer facing Web applications it’s just not there yet.

So what’s the bottom line? We have to learn how to develop Web applications that won’t require installing any new software on the user’s machines. Today it’s DHTML or, let’s stick to the modern terminology, HTML5 stack.

In the unfortunate event of needing to support both new and old HTML and CSS implementations you can use HTML5 Boilerplate that is not a framework, but a template for creating a new HTML project that will support HTML5 and CSS3 elements but will work even in the hostile environments of the older browsers. It’s like broadcasting a TV show in HD, but letting the cavemen with the 50-year old black-and-white tubes watching it too.

HTML Boilerplate comes is a really simple way to start your project pre-packaged with solutions and workarounds offered by well known gurus in the industry. Make no mistake, your codebase may be larger that you wanted - for example, the initial CSS starts with 500 lines accommodating the old and new browsers, but it may be your safety net.

Tip Watch this screencast by Paul Irish, a co-creator of HTML5 Boilerplate. You can also read the current version of the Getting started with HTML5 Boilerplate on Github.

Overview of Selected HTML 5 Tags

In this section we’ll overview a small set of the new HTML5 tags and attributes that are very practical for enterprise Web developers. For example, we are not going to review the <canvas> tag that allows you to draw freely in a predefined rectangular area. But we will show you some HTML5 goodies that are practical and useful for Web forms.

HTML5 Forms: Brief Overview

It’s hard to imagine an enterprise Web application that is not using forms. At the very minimum the Contact Us form has to be there. A login view is yet another example of the HTML form that almost every enterprise application needs. Our sample application Save Sick Child will need it too.

We’ll start with the prompts. Showing the hints or prompts right inside the input field will save you some screen space. HTML5 has a special attribute placeholder.

HTML5 New APIs

TODO

Advanced Introduction to JavaScript

This chapter is dedicated to the JavaScript programming language. Our challenging goal is "From Zero to Hero in 50 pages". While in the future chapters you’ll see how JavaScript frameworks can greatly minimize the amount of the JavaScript code that you need to write manually, you still need to understand the language itself.

This chapter starts with basics of the language, but then it quickly progresses to such advanced topics as prototypal inheritance, callbacks, and closures. If you prefer fat manuals covering each and every detail of programming languages, we can recommend you the book "JavaScript: The Definite Guide", Sixth Edition by David Flanagan.

Besides the JavaScript coverage this chapter includes a section on the tools (IDEs, debuggers, Web inspectors et al.) that will make your development process more productive.

Important While you can skip some sections of this book as not relevant to your needs, we recommend you to read each section of this chapter in order. Most of the materials presented here expect you to understand the previous content of this chapter.

JavaScript: A Brief History

The JavaScript programming language was designed in 1995 by Brendan Eich, who was working for Netscape Communications Corporation at the time. His goal was to allow developers create more interactive Web pages. Initially the name of this language was Mocha, then LiveScript, and finally Netscape agreed with Sun Microsystems, creator of Java to rename it to JavaScript.

A year later, the language was given to an international standards body called ECMA, which formalized the language into ECMAScript standard so that other Web browser vendors could create their implementation of this standard. JavaScript is not the only language created based on the ECMAScript specification - ActionScript is a good example of another popular dialect of ECMAScript.

To learn more about the history of JavaScript from the source watch the Brendan Eich’s presentation "JavaScript at 17" at O’Reilly’s conference Fluent 2012.

Vast majority of today’s JavaScript code is being executed by the Web browsers, butthere are JavaScript engines that can execute JavaScript code independently. For example, Google’s V8 JavaScript engine implements ECMAScript 5 and is used not only in the Chrome browser, but can run in a standalone mode and can be embedded in any C++ application. Using the same programming language on the client and the server is the main selling point of node.js, which runs in V8. Oracle’s Java Development Kit (JDK) 8 will include the JavaScript engine Nashorn that not only can run on both the server and the client computers, but also allows to embed the fragments of JavaScript into Java programs.

In the 90th, JavaScript was considered a second class language used mainly for prettifying Web pages. In 2005 the techniques known as AJAX (see Chapter 4) made a significant impact to the way Web pages were built. With AJAX, the specific content inside the Web page could be updated without the need to make a full page refresh. For example, Google’s gmail that inserts just one line at the top of your input box whenever the new email arrives - it doesn’t re-retrieve the entire content of your Inbox from the server.

AJAX gave a second birth to JavaScript. But the vendors of Web browsers were not eager to implement the latest specifications of ECMAScript. Browsers’ incompatibility and lack of good development tools prevented JavaScript from becoming the language of choice for Web applications. Let’s not forget about the ubiquitous Flash Player – an excellent VM supported by all desktop Web browsers. Rich Internet Applications written in ActionScript were compiled into the byte code and executed by Flash Player on the user’s machine inside the Web browser.

If AJAX saved JavaScript, then rapid proliferation of tablets and smartphones made it really hot. Today’s mobile devices come equipped with modern Web browsers, and in the mobile world there is no need to make sure that your Web application will work in the 4-year old Internet Explorer 8. Adobe’s decision to stop supporting Flash Player in the mobile Web browsers is yet another reason to turn to JavaScript if your Web application has to be accessed from smartphones or tablets.

ECMASript, 5th Edition has been published in 2009 and is currently supported by all modern Web browsers. If you are interested in discovering if specific features of ECMAScript 5 are supported by a particular Web browser, check the latest version of the ECMAScript 5 compatibility table. At the time of this writing the snapshot of the Chrome Browser v. 22 looks as in [FIG2-1] below:

images/fig_02_01.jpg
Figure 1. ECMAScript 5 Compatibility Sample Chart

JavaScript became the lowest common denominator available on thousands of different devices. Yes, the JavaScript engines are not exactly the same on thousands devices that people use to login to Facebook, but they are pretty close, and using some of the JavaScript frameworks spare you from worrying about their incompatibilities.

JavaScript is an interpreted language that arrives to the Web browser as text. The JavaScript engine optimizes and compiles the code before the execution. If the JavaScript engine is a part of a Web page, the browser will load and execute the JavaScript code embedded or referenced between the HTML tags <script> and </script>. JavaScript was originally created for Web browsers, which were supposed to display whatever content has successfully arrived. What if an image has not arrived from the server? You’ll see a broken image icon. What if erroneous JavaScript code with syntax errors has arrived to the browser? Well, the engine will try to execute whatever has arrived. The end users may appreciate such browser’s forgiveness when at least some content is available, but the software developers should be ready to spend more time debugging (in multiple browsers) the errors that could have been caught by compilers in other programming languages.

Why Declaring JavaScript Variables

JavaScript is a weakly typed language hence the developers don’t have a luxury of strong compiler’s help that Java or C# developers enjoy. This is easily explainable. Imagine that if in Java or C# instead of declaring variables of specific data types everything would be of type Object, and you could assign to it any value – a string, a number, or a custom object Person. This would substantially complicate the ability of the compiler to weed out all possible errors. You don’t need to declare variables in JavaScript – just assign a value and the JavaScript engine will figure out the proper type during the execution of your code.For example, the variable named girlfriend will have a data type of String:

girlfriendName=“Mary”;

Since I haven’t used the keyword var in front of girlfriend, this variable will have the global scope. Variables declared with var inside functions are local. Consider the following function declaration:

function addPersonalInfo(){
   var address ="123 Main Street";      // local String variable
   age=25;                              // global Number variable
   var isMarried = true;                // local boolean variable
       isMarried = "don't remember";    // now it's of String type
}

The variables address and isMarried are visible only inside the function addPersonalInfo(). The variable age becomes global because of omission of the keyword var. In Chapter 3, you’ll see an example of how to limit the scope of the variables to avoid polluting the global name space.

The variable isMarried changes its type from Boolean to String during the execution of the above script, and JavaScript engine won’t complain assuming that the programmer knows what she’s doing. So be ready for the run-time surprises and allocate a lot more time for testing than with programs written in compiled languages.

Yet another moving part is the JavaScript engine where your code will run. Unless you are developing for strictly controlled enterprise environment you can’t assume that the end-user will have the same runtime as yours. You must test your code in multiple Web browsers.

Which IDE to Use

Selecting an Integrated Development Environment (IDE) that supports JavaScript is a matter of your personal preference. Since there is no compilation stage and most of your debugging will be done using the Web browser tools, picking a text editor that supports syntax highlighting is all that most developers need. For example, there is an excellent commercial text editor Sublime Text 2. Among many programming languages this editor understands the keywords of HTML, CSS, and JavaScript, and it offers not only syntax highlighting, context sensitive help, and auto-complete too.

If you are coming from the Java background, the chances are that you are familiar with free and open sourced Eclipse IDE. In this case install the Eclipse plugin VJET by eBay.

Oracle’s IDE NetBeans 7.3 and above support HTML5 and JavaScript development and includes JavaScript debugger that allows your code to connect to the Web browser, while debugging inside the IDE. If you prefer Microsoft technologies, they offer excellent JavaScript support in Visual Studio 2012.

In this book we’ll use an Eclipse-based Aptana Studio 3 IDE. Aptana Studio is available free of charge. Aptana Studio comes with embedded Web Server so you can test your JavaScript code without the need to start any additional software. In this chapter we’ll use Aptana Studio IDE to illustrate the features of JavaScript, and in the next chapter you’ll be working with a number of Aptana projects that will lead you through the development of the first version of our Save Sick Child Web application.

For the real world development we recommend using commercial IDE WebStorm from JetBrains. In addition to smart context sensitive help, auto-complete, and syntax highlighting it offers HTML5 templates, and the code coverage feature that identifies the code fragment that haven’t been tested. All of the editors and IDEs listed here are either available for free or are priced in the area of $60 USD. Try them all and pick the one that best fits your coding habits.

Getting Familiar with Aptana IDE

Download and install Aptana Studio 3 from http://aptana.com. Start Aptana and close the start page it displays by clicking on the little X on the tab. Then customize the color theme of this IDE by clicking the rainbow-colored circle on its toolbar. We usually select the theme called Eclipse. After the first start of Aptana you’ll see the message on the left side that reads “There are no projects in your workspace. To get started, please create or import an existing one.”

If you want to start playing with the code samples that come with this book, click on the button Import Project, select the General | Archive file. Find the zip file you’d like to use, e.g. chapter2.zip, and press Finish. The project from the selected zip file will be imported into the Aptana’s workspace, which is nothing more than a folder on the disk where the source code will reside. When you work in Aptana IDE you see a set of views (panels). This set is called perspective. For Web projects Aptana uses Web perspective, which is indicated at the top right corner. Pressing the icon with a little pus sign at the top right allows to open another perspective with its own set of views.

Let’s get started with creating a project from scratch by pressing the button Create Project on the left. You could have also created a new Web Project using the File menu. On the next window you’ll need to select a wizard, and we’ll be always working with Web Projects throughout this book. The next window will offer you to select a project template - let’s stick to the simplest one - Default Project. Name it MyFirstProject.

To add an HTML file to this project select the menu File | New From Template | HTML | HTML5 Template. Aptana will offer you new_file.html the name of this file - no need to change it for now. Just press finish and you’ll see a window similar to the one shown on [FIG2-2].

images/fig_02_02.jpg
Figure 2. Aptana IDE with one HTML5 file

Right-click on the new_file.html and select the menu Run as JavaScript Web project. Don’t get upset that there is no JavaScript code there yet - we’ll add it pretty soon. Aptana starts its built-in Web server that by default runs on the port 8020 (it’s configurable in Aptana Preferences). The Web browser opens up and displays the page that looks like the one in [FIG2-3]. Aptana has used its default template to generate HTML file. The template can be changed to your liking, and you can read about it in Aptana’s documentation at http://bitly.com/LRqRdU.

Tip If you have your index.html open in Aptana’s editor, you can simply press the green triangle on the toolbar and run this file in the Web browser.
images/fig_02_03.jpg
Figure 3. Running MyFirstProject
Tip To configure the Web Browser that Aptana should open by default, open its Preferences window and select the Web browser of your choice under the General section. Many examples in this chapter use the Firefox with installed add-on Firebug, so start with making Firefox your default browser.

Adding JavaScript to HTML

If your JavaScript is a part of HTML document, typically, you’ll be adding your <script> tags at the end of HTML file. The reason is simple - your JavaScript code may be manipulating with HTML elements, and you want them to exist by the time the script runs. The other way to ensure that the code is not running unless the Web page has loaded is by catching window’s load event, and you’ll see such example later in this chapter in the section on browser’s events. Some JavaScript frameworks may have their own approach to dealing with HTML content and in Chapter 7 you’ll see that the main HTML file of the Web application written with Ext JS framework has <script> tags followed by the empty <body> tags. But let’s keep things simple for now.

Add the following fragment at the very end (right above the closing </body> tag) of the new_file.html from [FIG2-2].

<script>
   alert("Hello from JavaScript");
</script>

Run the new_file.html in Aptana and you’ll see the following output in your Web browser:

images/fig_02_04.jpg
Figure 4. Running MyFirstProject with JavaScript at the bottom

Note that the Alert popup box is shown on top of the Web page that already rendered all of its HTML components. Now move the above code up to the end of the <head> section and re-run new_file.html. The picture is different now - the Alert box is shown before the HTML rendering is complete.

images/fig_02_05.jpg
Figure 5. Running MyFirstProject with JavaScript at the top

In this simple example this doesn’t cause any malfunctioning of the code, but if our JavaScript would need to manipulate with HTML elements, we’d run into issues of accessing non-existent components. Beside simple Alert box, JavaScript has Confirm and Prompt boxes, which allow asking OK/Cancel type of questions or request some input from the user.

Tip In a real life you won’t be deploying your projects under Aptana’s internal Web server. When you code is tested you can FTP it to a remote server of your choice, e.g. Apache Web Server or IIS. Right-click on your Aptana project and select the menu option Publish. This will allow you to configure the FTP connection to your remote server and publish your working code there as you wish.

Debugging JavaScript in Web Browsers

The best way to learn any program is to run it step by step through a debugger. While some people appreciate using debuggers offered by Aptana, NetBeans, or Visual Studio, we prefer to debug using great tools offered by the major Web browsers:

  • Firefox: FireBug add-on

  • Chrome: Developer Tools

  • Internet Explorer: F12 Developer Tools

  • Safari: the menu Develop

  • Opera: Dragonfly

We’ll be doing most of the debugging in FireBug or Chrome Developer Tools. Both of them provide valuable information about your code and are easy to use. To get FireBug go to www.getfirebug.com and press the red button Install Firebug and follow the instructions. In Firefox, open the Firebug panel from the menu View.

images/fig_02_06.jpg
Figure 6. FireBug Console

Select the Console option on the Firebug toolbar and enter alert("Hello from JavaScript") after the >>> sign and you’ll see the Alert box. To enter multi-line JavaScript code press the little circle with a caret at the bottom right corner and FireBug will open a panel on the right, where you can enter and run your JavaScript code.

This was probably the last example where we used the Alert() popup box for debugging purposes. All JavaScript debuggers support the console.log() for printing debug information. Consider the following example that illustrate strict equality operator ===. Yes, it’s three equal signs in a row. This operator evaluates to true if the values are equal and the data types are the same.

var age=25;

var ageStr="25";

if (age==ageStr){
  console.log("The values of age and ageStr are equal");
}

if (age===ageStr){
 console.log("The values of age and ageStr are strictly equal");
} else{
 console.log ("The values of age and ageStr are not strictly equal");
}

Running this code in the FireBug console produces the following output:

images/fig_02_07.jpg
Figure 7. Using console.log() for the debug output
Tip You can also use console.info(), console.debug(), and console.error() so the debuggers may highlight the output with different colors or mark with different icons.
Tip For more information about debugging JavaScript refer to the code samples illustrated in [FIG2-8] and [FIG2-9].

JavaScript Functions. Gentle Introduction

Now comes the chicken or the egg dilemma. What should be explained first - functions or objects? Understanding of objects is needed for some of the function code samples and visa versa. We’ll start with simple function use cases, but will be switching to objects as needed.

Many of the readers can have experience with object-oriented languages like Java or C#, where classes can include methods implementing required functionality. Then these methods can be invoked with or without instantiation of the objects. If a JavaScript object includes functions they are called methods. But JavaScript functions don’t have to belong to an object. You can just declare a function and invoke it. Just like this:

//Function declaration
function calcTax (income, dependents){
   var tax;
   // Do stuff here
   return tax;
}

//Function invocation
calcTax(50000, 2);
var myTax = calcTax(50000,2);

Please note that the data types of the function parameters income and dependents are not specified. We can only guess that they are numbers based on their names. If a software developer won’t bother giving meaningful names to function parameters, the code becomes difficult to read. After the function calcTax() is invoked and complete, the variable myTax will have the value returned by the function. In the above code sample the JavaScript engine will not evaluate the function calcTax() until it’s actually invoked.

Another important thing to notice is that our function has a name calcTax. But this is not always the case - JavaScript allows functions to be anonymous. If you see the line of code where the keyword function is preceded by any other character this is not a function declaration, but a function expression. Consider the following variation of the tax calculation sample:

//Function expression
var doTax=function (income, dependents){
        //do stuff here
   return tax;
}

//Function invocation
var myTax=doTax(50000,2);

In the code above the function keyword is being used in the expression - we assign the anonymous function to the variable doTax. After this assignment just the text of the function is assigned to the variable doTax - the anonymous function is not being invoked just yet. It’s important to understand that even though the code of this anonymous function ends with return tax; actually, the tax calculation and return of its value is not happening until the doTax() is invoked. Only then the function is evaluated and the variable myTax will get whatever value this function returns.

Yet another example of a function expression is when it’s placed inside the grouping operator - parentheses as shown below:

(function calcTax (income, dependents){
   // Do stuff here
});

Another interesting concept of JavaScript is self-executing functions. Adding an extra pair of parentheses will cause the function expression located in the first set of parentheses to be executed right away.

(function calcTax (income, dependents){
   // Do stuff here
})();

The first set of parentheses hides its internal code from the outside world creating a scope or a closed ecosystem, where the function’s code will operate. Try to add a line invoking this function after the last line in the above code sample, e.g. calcTax(50000,2), and you’ll get an error - "calcTax is not defined". There is a way to expose some of the internal content of such a closure and you’ll see how to do it later in this chapter.

JavaScript Objects. Gentle Introduction

JavaScript objects are simply unordered collections of properties. You can assign new or delete existing properties from the objects during the runtime whenever you please. In classical object oriented languages there are classes and there are objects. For example, based on one Java a class you can create multiple instances of its objects.

Note The ECMAScript 6 specification will include classes too, but since it’s a work in progress we won’t consider them as something useful in the today’s world. If you’d like to experiment with the upcoming features of JavaScript, download the Chrome Canary browser, go to chrome:flags and enable experimental JavaScript.

In JavaScript you can create objects using one of the following methods:

  • Using object literals

  • Using new Object() notation

  • Using Object.create()

  • Using constructor functions and a new operator.

Note In JavaScript everything is an Object. Think of Object as of a root of of the hierarchy of all objects used in your program. All your custom objects are descendants from Object.

Object Literals

The easiest way to create a JavaScript object is by using the object literal notation. The code sample below starts with a creation of an empty object. The second line creates an object with one property salary and assigns the value of 50000 to it. Finally, the instance of one more object pis created and the variable person points at it.

var t = {}             // create an instance of an empty object

var a = {salary: 50000}; // an instance with one property

// Store the data about Julia Roberts
var person = { lastName: ”Roberts”,
               firstName: ”Julia”,
                     age: 42
             };

This object has three properties: lastName, firstName, and age. Note that in object literal notation the values of these properties are specify using colon. You can access the properties of this person using the dot notation, e.g. person.LastName. But JavaScript allows yet another way of accessing the object properties by using square bracket syntax, for example person["lastName"]. In the next code sample you’ll see that using the square brackets is the only way to access the property.

 var person = {
       "last name": "Roberts",
       firstName: "Julia",
             age: 42};

var herName=person.lastName;          // 1

console.error("Hello " + herName);    // 2

herName=person["last name"];           // 3

person.salutation="Mrs. ";

console.log("Hello "+ person.salutation + person["last name"]); // 4
1 The object person doesn’t have a property lastName, but no error is thrown
2 This will print "Hello undefined"
3 Using and alternative way of referring to an object property
4 This will print "Hello Mrs. Roberts"
Tip It’s a good idea to keep handy a style guide of any programming language, and we know two of such documents for JavaScript. Google has published their version of JavaScript Style Guide at http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml. A more detailed Airbnb JavaScript Style Guide is available as a github project at https://github.com/airbnb/javascript. And the github version of the JavaScript style guide is located at https://github.com/styleguide/javascript.

Objects can contain other objects. If a property of an object literal is also an object, you just need to specify the value of this property in an extra pair of curly braces. For example, you can represent the telephone of a person as an object having two properties: the type and the number. The following code snippet adds a nested object to store a work phone as a nested object inside the person’s object. Run this code in the FireBug’s console and it’ll print "Call Julia at work 212-555-1212".

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phone:{
                      type: "work",
                      numb: "212-555-1212"
                 }
            };
console.log("Call " + p.firstName + " at " + p.phone.type + " " + p.phone.numb );

What if a person has more then one phone? We can change the name of the property phone to phones and instead store an array of objects. JavaScript arrays are surrounded by square brackets, and they are zero based. The following code snippet will print "Call Julia at home 718-211-8987".

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phones:[{
                      type: "work",
                      numb: "212-555-1212"
                 },
                 {
                      type: "home",
                      numb: "799-211-8987"

                 }]
            };
console.log("Call " + p.firstName + " at " + p.phones[1].type + " " + p.phones[1].numb );
Methods in Object Literals

Functions defined inside objects are called methods. Defining methods in object literals is similar to defining properties - provide a method name followed by a colon and the function declaration. The code snippet below declares a method makeAppoyntment() to our object literal. Finally, the line p.makeAppointment(); invokes this new method, which will print the message on the console that Steven wants to see Julia and will call at so-and-so number.

var p = { lastName: "Roberts",
                firstName: "Julia",
                age: 42,
                phones:[{
                      type: "work",
                      numb: "212-555-1212"
                 },
                 {
                      type: "home",
                      numb: "718-211-8987"

                 }],
                makeAppointment: function(){
                    console.log("Steven wants to see  " + this.firstName +
                                 ". He'll call at " + this.phones[0].numb);
                }
            };

p.makeAppointment();
Note Since we already started using arrays, it’s worth mentioning that arrays can store any objects. You don’t have to declare the size of the array upfront and can create new arrays as easy as var myArray=[] or var myArray=new Array(). You can even store function declarations as regular strings, but they will be evaluated on the array initialization. For example, during the greetArray initialization the user will see a prompt asking to enter her name, and, when it’s done, the greetArray will store two strings. The output of the code fragment below can look like "Hello, Mary".
var greetArray=[
    "Hello",
    prompt("Enter your name", ”Type your name here")
];

console.log(greetArray.join(","));

We’ve briefly covered object literals, and you to start using them. In Chapter 4 you’ll be learning about JSON - a popular data format used as replacement for XML in the JavaScript world. Then you’ll see how similar are the syntax of JSON and JavaScript object literals. Now we’ll spend a little bit of time delving into JavaScript functions, and then - back to objects again.

Constructor Functions

JavaScript functions are more then just some named pieces of code that implements certain behavior. They also can become objects themselves by a magic of the new operator. To make things even more intriguing, the function calls can have memories, which will be explained in the section about closures.

If a function is meant to be instantiated with the new operator it’s called a constructor function. If you are familiar with Java or C# you understand the concept of a class constructor that is being executed only once during the instantiation of a class. Now imagine that there is only a constructor without any class declaration that still can be instantiated with the new operator as in the following example.


function Person(lname, fname, age){
         this.lastName=lname;
         this.firstName=fname;
         this.age=age;
};

// Creating 2 instances of Person
var p1 = new Person(“Roberts”,“Julia”, 42);

var p2 = new Person(“Smith”, “Steven”, 34);

This code declares the function Person and after that, it creates two instances of the Person objects referred by the variables p1 and p2 accordingly. This is what the statement functions are objects means.

Note According to common naming conventions the names of the constructor functions are capitalized.

Objects can have methods and properties, right? On the other hand, functions are objects. Hence functions can have methods and properties too. If you declare a function marryMe() inside the constructor function Person, marryMe() becomes a method of Person. This is exactly what we’ll do next. But this time we’ll create an HTML file that includes the <script> section referring to the JavaScript code sample located in a separate file.

If you want to try it hands-on, create a new file in your Aptana project by selecting the menu File | New | File and give it a name marryme.js. Agree with a suggested default JavaScript template, and key in the following content into this file:


function Person(lname, fname, age){
         this.lastName=lname;
         this.firstName=fname;
         this.age=age;

         this.marryMe=function(person){
                console.log("Will you marry me, " + person.firstName);
         };

};

var p1= new Person("Smith", "Steven");
var p2= new Person("Roberts", "Julia");

p1.marryMe(p2);

The code above uses the keyword this that refers to the object (a.k.a. context) where the code will execute. If you are familiar with the meaning of this in Java or C#, it’s similar, but not exactly the same, and we’ll illustrate it in the section titled "Who’s this". The method marryMe() of one Person object takes an instance of another Person object and makes an interesting proposition: "Will you marry me, Julia".

This time we won’t run this code in the Firebug’s console, but rather will include it in the HTML file. In Aptana, create a new File | New | File, enter marryme.html as the file name and press the button Finish. Don’t press the button Next as it’ll offer you to select from one of the HTML templates, but this would generate lots of HTML content, which is not needed for our code sample. Just type in the following in the newly created empty file marryme.html.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

        <body>
                <h1>Making Proposal</h1>

                <script src="marryme.js"></script>
        </body>
</html>

Debugging JavaScript in Firebug

In Aptana, right-click on the file marryme.html and select the option Run As | JavaScript Web Application. We continue using Firefox as Aptana’s default browser, and you’ll see it open a new Web page that reads "Making Proposals". Open the Firebug using the View menu, refresh the page and switch to the Firebug’s tab Script. You’ll see the split panel with the JavaScript code from marryme.js on the left.

images/fig_02_08.jpg
Figure 8. Firebug’s Script panel

Let’s set a breakpoint inside the method marryMe() by clicking in the Firebug’s gray area to the left of the line 7. You’ll see a red circle that will reveal a yellow triangle as soon as your code execution will hit this line. Refresh the content of the browser to re-run the script with a breakpoint. Now the execution stopped at line 7, the right panel contains the runtime information about the objects and variables used by your program.

images/fig_02_09.jpg
Figure 9. Firebug’s Script panel at a breakpoint

On the top of the left panel you’ll see usual for debuggers curved arrows (Step Into, Step Over, Step Out) as well as triangular button to continue code execution. The right panel depicts the information related to this and global Window objects. In [FIG2-9] this represents the instance of the Person object represented by the variable p1 (Steven Smith). To see the content of the object, received by the method marryMe() you can add the watch variable by clicking on the text "New watch expression…" and entering person - the name of the parameter of marryMe(). [FIG2-10] shows the watch variable person (Julia Roberts) that was used during the invocation of the method marryMe().

images/fig_02_10.jpg
Figure 10. Firebug’s Script panel at a breakpoint

Now click on the Firebug’s Net panel, which shows what goes over the network during communication between the Web browser and Web server. Figure 2-11 shows a screen shot of the Net panel where we clicked on the Headers tab for marryme.html and the Response tab of marryme.js. The code 200 for both files means that they arrived successfully to the browser. It also shows the IP address of the Web server they came from, their sizes, and plenty of other useful information. Both Script and Net panels of Firebug or any other developers tools are your best friends of any Web developer.

images/fig_02_11.jpg
Figure 11. Firebug’s Net panel

We like Firebug, but testing and debugging should be done in several Web browsers. Besides Firebug, we’ll be using excellent Google Chrome developers tools. Their menus and panels are similar and we won’t be including such mini-tutorials on using such tools - you can easily learn them on your own.

Notes on Arrays

A JavaScript array is a grab bag of any objects. You don’t have to specify in advance the number of elements to store, and there is more than one way to create and initialize array instances. The following code samples are self-explanatory.


var myArray=[];
    myArray[0]="Mary";
    myArray[2]="John";

// prints undefined John
console.log(myArray[1] + " " + myArray[2]);

var states1 = ["NJ", "NY", "CT", "FL"];

var states = new Array(4);  // size is optional

states[0]="NJ";

states[1]="NY";

states[2]="CT";

states[3]="FL";

// remove one array element
delete states[1];


// prints undefined CT length=4
console.log(states[1] + " " + states[2] + " Array length=" + states.length);

// remove one element starting from index 2
states.splice(2,1);

// prints undefined  FL length=3
console.log(states[1] + " " + states[2] + " Array length=" + states.length);

Removing elements with delete creates gaps in the arrays while using the array’s method splice() allows to remove or replace the specified range of elements closing gaps.

The next code sample illustrates an interesting use case when we assign a string and a function text as array elements to mixedArray. During array initialization the function promt() will be invoked, the user will be prompted to enter name, and after that, two strings will be store in mixedArray, for example "Hello" and "Mary".


var mixedArray=[
    "Hello",
    prompt("Enter your name", ”Type your name here")
];

Prototypal Inheritance

JavaScript doesn’t support classes, at least till the ECMAScript 6 will become a reality. But JavaScript allows you to create objects that inherit properties and methods of other objects. By default, all JavaScript objects are inherited from Object. Each JavaScript construction function has a special property called prototype, which points at this object’s ancestor. If you want to create an inheritance chain where an instances of constructor function ObjectB extend ObjectA just write one line of code: ObjectB.prototype=ObjectA;.

images/fig_02_12.jpg
Figure 12. Prototypal Inheritance

Consider two constructor functions Employee and Person shown in the code snippet below.They represent two unrelated objects. But assigning the Person object to the prototype property of Employee creates an inheritance chain, and now the object emp will have all properties defined in both Employee and Person.


function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];
}

function Employee(name, title){
        this.name=name;
        this.title=title;
}

// All instances of Employee will extend Person
Employee.prototype = new Person();            // 1

var emp=new Employee("Mary", "Specialist"); // 2

console.log(emp);      // 3
1 Assigning an ancestor of type person
2 Instantiating Employee
3 Printing the object referred by emp will output [object Object]. It happens because each object has a method toString(), and if you want it to output useful information - override it. You’ll see how to do it later in this section.

We want to stress, that the property prototype exists on constructor functions. After creating specific instances of such objects you may see that these instances have another property called proto. At the time of this writing this property is not a standard yet and won’t be supported in some older browsers, bit ECMAScript 6 will make it official. To illustrate the difference between prototype and proto let’s add the following piece of code to the above sample:


//Create an instance of Person and add property dependents
var p=new Person();
p.dependents=1;                                 // 1


var emp2=new Employee("Joe", "Father");

//This employee will have property dependents

emp2.__proto__=p;                               // 2

console.log("The number of Employee's dependents " + emp2.dependents); // 3
1 Creating an instance of Person and adding an extra property dependents just for this instance
2 Assigning this instance to the __proto__ property of one instance
3 The code will properly print 1 as a number of dependents of the Employee instance represented by the variable emp2. The variable emp from the previous code snippet won’t have the property dependents.

To try it hands-on, open the file WhoIsYourDaddy.html in Aptana. Just for a change, this time we’ll use Google Chrome Developer Tools by opening the menu View | Developer | Developer Tools. Set the breakpoint at the last line of the JavaScript, refresh the Web page content, and add the watch expressions for the variables p, emp, and emp2. When the JavaScript code engine runs into emp2.dependents it tries to find this property in property on the Employee object. If not found, the engine checks all the objects in the prototypal chain (in our case it’ll find it in the object p) all the way up to the Object if need be.

Tip If you need to do some programmatic manipulations with only those properties that are defined on the specific object (not in its ancestors) do the check with the method hasOwnProperty().
images/fig_02_13.jpg
Figure 13. The instance-specific __proto__ variable
Tip You can find a tutorial on using Google Chrome Developer Tools at https://developers.google.com/chrome-developer-tools/. The cheatsheet of Chrome developer Tools is located at http://anti-code.com/devtools-cheatsheet/.

Please not the difference in the content of the variables __proto__ of the instances represented by emp and emp2. These two employees are inherited from two differnet objects Person. Isn’t it scary? Not really.

Where to Declare Methods

If you take a closer look at the screenshot from [FIG2-13] you’ll see that the Person and Employee objects have redundant properties name and title. We’ll deal with this redundancy in the section titled "Call and Apply". But first let’s introduce and cure the redundancy in method declarations when the prototypal inheritance is used.

Let’s add a method to addSubordinate() to the ancestor object Person that will populate its array subordinates. Who knows, maybe an object Contractor (descendant of a Person) will need to be added in the future, so the ancestor’s method addSubordinate() can be reused. First, we’ll do it the wrong way to illustrate the redundancy problem, and then we’ll do it right. Consider the following code:

// Constructor function Person
function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];

    // Declaring method inside the constructor function
        this.addSubordinate=function (person){
                this.subordinates.push(person)
        }


}

// Constructor function Employee
function Employee(name, title){
        this.name=name;
        this.title=title;
}

// Changing the inheritance of Employee
Employee.prototype = new Person();

var mgr =  new Person("Alex", "Director");
var emp1 = new Employee("Mary", "Specialist");
var emp2 = new Employee("Joe", "VP");

mgr.addSubordinate(emp1);
mgr.addSubordinate(emp2);
console.log("mgr.subordinates.length is " + mgr.subordinates.length);

The method addSubordinate() here is declared inside the constructor function Person, which becomes an ancestor of the Employee. After instantiation of two Employee objects the method addSubordinate() is duplicated for each instance.

Let’s use Google Chrome Developer Tools profiler to see the sizes of the objects allocated on the Heap memory. But first we’ll set up two breakpoints - one before, and one after creating our instances as shown on [FIG2-14].

images/fig_02_14.jpg
Figure 14. Preparing Breakpoints Take 1.

When the execution of the code will stop at the first breakpoint, we’ll switch to the Profiler tab and take the first Heap snapshot. Upon reaching the second breakpoint we’ll take another Heap snapshot. The dropdown at the status bar allows to view the objects allocated between the snapshots 1 and 2. [FIG2-15] depicts this view of the profiler. Note that the total size (the Shallow Size column) for the Person instances is 132 bytes. Employee instances weigh 104 bytes.

images/fig_02_15.jpg
Figure 15. Objects allocated between snapshots 1 and 2

Now we’ll change the code to declare the method not inside the Person constructor function, but on it’s prototype - and this is the right way to declare methods in functions to avoid code duplication.

// Constructor function Person
function Person(name, title){
        this.name=name;
        this.title=title;
        this.subordinates=[];

}

//Declaring method on the object prototype
Person.prototype.addSubordinate=function(subordinate){
   this.subordinates.push(subordinate);
   return subordinate;
}

// Constructor function Employee
function Employee(name, title){
        this.name=name;
        this.title=title;
}

// Changing the inheritance of Employee
Employee.prototype = new Person();

var mgr =  new Person("Alex", "Director");
var emp1 = new Employee("Mary", "Specialist");
var emp2 = new Employee("Joe", "VP");

mgr.addSubordinate(emp1);
mgr.addSubordinate(emp2);
console.log("mgr.subordinates.length is " + mgr.subordinates.length);

Similarly, we’ll set up two breakpoints before and after object instantiation as shown in <<>FIG2-16>.

images/fig_02_16.jpg
Figure 16. Preparing Breakpoints Take 2.

Let’s take two more profiler snapshots upon reaching each of the breakpoint. While the weight of the Employee instances remained the same (104 bytes), the Person instances became lighter: 112 bytes. While 20 bytes may not seem like a big deal, if you’ll need to create hundreds or thousands of object instances it adds up.

images/fig_02_17.jpg
Figure 17. Objects allocated between snapshots 3 and 4

So if you need to declare a method on the object that will play a role of the ancestor, do it on the prototype level. The only exception to this rule is the case when such method needs to use some object specific variable that’s different for each instance - in case declare methods inside the constructors (see the section on closures for details).

Note All modern Web browsers support the function Object.create(), which creates a new object based on another prototype object. For example, var objectB=Object.create(objectA);. What if you must support an older browser and need such "create by example" functionality? Of course, you can always create a custom arbitrarily named function with the similar functionality as the latest implementation of Object.create(). But the future-proof approach is to create the missing methods with the same signatures and on the same objects as the latest ECMAScript specification prescribes. In case of Object.create() you can use the implementation offered by Douglas Crockford:
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

Such approach of custom implementation of missing pieces according to the latest ECMAScript specifications or W3C drafts is known as polyfills. People who can’t wait till the browser vendors will implement the newest functionality create cross-browser polyfills and some of them submit their source code to the public domain. You can find a number of polyfills in the git repository of the Modernizr project. The Web site http://caniuse.com/ contains the current information about browser’s support of the latest HTML5, JavaScript, and CSS features.

Method overriding

Since JavaScript allows declaring methods on an object as well as on its prototype, overriding a method becomes really simple. The following code sample declares the method addSubordinate() on the prototype of the Person object, but then the object p1 overrides this method.

function Person(name, title){

  this.name=name;
  this.title=title;
  this.subordinates=[];
}

Person.prototype.addSubordinate=function(person){

   this.subordinates.push(person);
   console.log("I'm in addSubordinate on prototype " + this);
}

var p1=new Person("Joe", "President");

    p1.addSubordinate=function(person){

    this.subordinates.push(person);
    console.log("I'm in addSubordinate in object " + this);
  }

var p2 = new Person("Mary", "Manager")

    p1.addSubordinate(p2);

Running the above code prints only one line: "I’m in addSubordinate in object [object Object]". This proves that the method addSubordinate() on the prototype level is overridden. We can also improve this example a little bit and override the method toString() on the Person. Just add the following fragment to the prior to instantiating p1.

Person.prototype.toString=function(){
   return "name:" + this.name +" title:" + this.title;
}

Now the code prints "I’m in addSubordinate in object name:Joe, title:President". Overriding the method toString() on objects is a common practice as it gives a textual representation of your objects.

Scope or who’s this?

You are about to read one of the most confusing sections in this book. The confusion is caused by some inconsistencies in JavaScript design and implementations by various browsers. Do you know what will happen if you’ll remove the keywords this from the toString() method from previous section? You’ll get an error - the variable title is not defined. Without the keyword this the JavaScript engine tries to find the variable title in the global namespace. Declaring and initializing the variable title outside of the Person declaration get rid of this error, but this is not what we want to do. Misunderstanding of the current scope can lead to difficult to debug errors.

Caution Interestingly enough replacing this.name with name doesn’t generate an error, but rather initializes the variable name with an empty string. Although name is not an officially reserved JavaScript keyword, there are articles in the blogosphere that don’t recommend using the word name as a variable name. Keep this list of reserved words handy to avoid running into an unpredictable behavior.

Let’s consider several examples that will illustrate the meaning of this variable in JavaScript. The code sample below defines an object myTaxObject and calls its method doTaxes(). Notice two variables with the same name taxDeduction - one of them has global scope and another belongs to myTaxObject. This little program was written for mafia and will apply some under the table deduction for the people who belong to Cosa Nostra.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         mafiaSpecial();  // invoking as a function
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

This code fragment illustrates the use of nested functions. The object method doTaxes() has a nested function mafiaSpecial(), which is not visible from outside of the myTaxObject, but it can be certainly invoked inside doTaxes(). What number do you think this code will print after the words "Will deduct "? Will it print three, four, or five hundred? Run this code in Firebug, Chrome Developer Tools or any other way and you’ll see that it’ll print 300!

But this doesn’t sound right, does it? The problem is that in JavaScript the context where the function executes depends on the way it was invoked. In this case the function mafiaSpecial() was invoked as a function (not a method) without specifying the object it should apply to, and JavaScript makes it operate in the global object, hence the global variable taxDeduction having the value of 300 is being used. So in expression this.taxDeduction the variable this means global unless the code is operated in the strict mode.

Note ECMAScript 5 introduced a restricted version of JavaScript called strict mode, which among other things places stricter requirements to variable declarations and scope identification. Adding "use strict" as the first statement of the method doTax() will make the context undefined, and it’ll print the error "this is undefined" and not 300. You can read about the strict mode at Mozilla’s developers site.

Let’s make a slight change to this example and take to control what this represents. When the object myTaxObject was instantiated its own this reference was created. The following code fragment stores this reference in additional variable thisOfMyTaxObject changes the game and the expression thisOfMyTaxObject.taxDeduction evaluates to 500.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
    var thisOfMyTaxObject=this;
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + thisOfMyTaxObject.taxDeduction);
         }

         mafiaSpecial();  // invoking as a function
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

You’ll see a different way of running a function in the context of the specified object using special functions call() and apply(). But for now consider one more attempt to invoke mafiaSpecial()`shown in the following example that uses `this.mafiaSpecial() notation.

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,    // object property

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         this.mafiaSpecial();  // trying to apply object's scope
    }
}

myTaxObject.doTaxes();  //invoking method doTaxes

Run the above code and it’ll give you the error "TypeError: this.mafiaSpecial is not a function" and rightly so. Take a closer look at the object myTaxObject represented by the variable this. The myTaxObject has only two properties: taxDeduction and doTaxes. The function mafiaSpecial is hidden inside the method doTaxes and can’t be accessed via this.

Call and Apply

Visualize the International Space Station, and add to the picture an image of a approaching space shuttle. After attaching to the docking bay of the station the shuttle’s crew performs some functions on the station (a.k.a. object) and then flies to another object or back to Earth. What is has to do with JavaScript? It can serve as an analogy for creating a JavaScript function that can operate in the scope of any arbitrary object. For this purpose JavaScript offers two special functions: call() or apply(). Both call() and apply() can invoke any function on any object. The only difference between them is that apply() passes required parameters to a function as an array, while call() uses a comma-separated list.

Tip Every function in JavaScript is a Function object. Both call() and apply() are defined in the Function object.

For example, a function calcStudentDeduction(income,numOfStudents) can be invoked in a context of a given object using either call() or apply(). Note that with call() parameters have to be listed explicitly, while with apply parameters are given as an array:

calcStudentDeduction.call(myTaxObject, 50000, 2);

calcStudentDeduction.apply(myTaxObject, [50000, 2]);

In the above example the instance of ‘myTaxObject` can be referred as this from within the function calcStudentDeduction() even though this is a function and not a method. The last example from the previous section can be re-written to invoke mafiaSpecial(). The following code will ensure that mafiaSpecial() has this pointing to `myTaxObject’ and will print on the console "Will deduct 500".

var taxDeduction=300;      // global variable

var myTaxObject = {

    taxDeduction: 400,

    doTaxes: function() {
         this.taxDeduction += 100;

         var mafiaSpecial= function(){
           console.log( "Will deduct " + this.taxDeduction);
         }

         mafiaSpecial.call(this);  // passing context to a function
    }
}

myTaxObject.doTaxes();

Callbacks

Can you live without using call() and apply()? Sure you can, but in JavaScript can easily create callbacks - you can pass the code of one function as a parameter to another function for execution in the latter function’s context. Most likely you’ve seen how event handlers are declared. If a user clicks on this button here’s the name of the handler function to call: myButton.addEventListener("click", myFunctionHandler)

It’s important to understand that you don’t not immediately call the function myFunctionHandler here - you are just registering it. If and only if the user will click on myButton then the callback myFunctionHandler has to be invoked in the context of the myButton object. The functions call() and apply() exist exactly for this purpose.

Let’s consider an example when you need to write a function that will take two arguments - and array with preliminary tax data and a callback function to be applied to each element of this array. The following code sample creates myTaxObject that has two properties: taxDeduction and the applyDeduction. The latter is a method with two parameters: array and a callback to be applied to this array.

var myTaxObject = {

    taxDeduction: 400, // state-specific  deduction

    // this function takes an array and callback as parameters
    applyDeduction: function(someArray, someCallBackFunction){

        for (var i = 0; i < someArray.length; i++){

            // Invoke the callback
           someCallBackFunction.call(this, someArray[i]);
        }

    }
}

// array
var preliminaryTaxes=[1000, 2000, 3000];

// tax handler function
var taxHandler=function(currentTax){
                   console.log("Hello from callback. Your final tax is " +
                   (currentTax - this.taxDeduction));
                }

// invoking applyDeduction passing an array and callback
myTaxObject.applyDeduction(preliminaryTaxes, taxHandler);

The above code invokes applyDeduction() passing it the array preliminaryTaxes and the callback function taxHandler that takes the currentTax and subtracts this.taxDeduction. By the time this callback will be applied to each element of the array the value of this will be known and this code will print the following:

Hello from callback. Your final tax is 600
Hello from callback. Your final tax is 1600
Hello from callback. Your final tax is 2600

You may be wondering, why passing the function to another object if we could take an array, subtract 400 from each of its elements and be done with it? The solution with callbacks gives you an ability to make the decision on what function to call during the runtime and call it only when a certain event happens. Callbacks allow you to do asynchronous processing. For example, you make an asynchronous request to a server and register the callback to be invoked if a result comes back. The code is not blocked and doesn’t wait until the server response is ready. Here’s an example from AJAX: request.onreadystatechange=myHandler. You register myHandler callback but not immediately call it. JavaScript functions are objects, so get used to the fact that you can pass them around as you’d be passing any objects.

Hoisting

A variable scope depends on where it was declared. You already had a chance to see that a variable declared inside a function with the keyword var is visible only inside this function. Some programming languages allow to narrow down the scope even further. For example, in Java declaring a variable inside any block of code surrounded with curly braces makes it visible only inside such a block. In JavaScript it works differently. No matter where in the function you declared the variable its declaration will be hoisted to the top of the function, and you can use this variable anywhere inside the function.

The following code snippet will print 5 even though the variable b has been declared inside the if-statement. It’s declaration has been hoisted to the top:

function test () {
    var a=1;

    if(a>0) {
        var b = 5;
    }
    console.log(b);

}

test();

Let’s make a slight change to the above code to separate the variable declaration and initialization. The following code has to console.log(b) statements. The first one will output undefined and the second will print 5 just as in the previous example.

function test () {
    var a=1;

    console.log(b);  // b is visible, but not initialized

    if(a>0) {
        var b;
    }

    b=5;

    console.log(b);  // b is visible and initialized
}

test();

Due to hoisting, JavaScript doesn’t complain when the first console.log(b) is invoked. It knows about the variable b, but its value is undefined just yet. By the time the second console.log(b) is called, the variable b was initialized with the value of 5. Just remember that hoisting just applies to variable declaration and doesn’t interferes with your code when it comes to initialization. JavaScript function declarations are hoisted too, and this is illustrated in the following code sample.

function test () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    function printB(){
        console.log(b);
    }
}

test();

This code will print 5. We can call the function printB() here because its declaration was hoisted to the top. But the situation changes if instead of function declaration we’ll use the function expression. The following code will give you an error "PrintB is not a function". Notice that it the error doesn’t complain about printB being undefined cause the variable declaration was hoisted, but since the function expression wasn’t the JavaScript engine doesn’t know yet that printB will become a function really soon. Anyway, moving the invocation line printB() to the bottom of the function test() cures this issue. Function expressions are not being hoisted.

function test () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    var printB = function(){
        console.log(b);
    }

}

test();

All code samples in this section first declare the function test() and then invoke it. This function test() is being called once and there is no reason to give it a name. Using so called self-invoked function notation allows to declare and automatically invoke the function (note the extra parentheses at the end of the following code).

(function () {
    var a=1;

    if(a>0) {
        var b;
    }

    b=5;

    printB();

    var printB = function(){
        console.log(b);
    }

})();

Function properties

Functions as any other objects can have properties. You can attach any properties to a Function object and their values can be used by all instances of this object. Static variables in programming languages with the classical inheritance is the closest analogy to function properties in JavaScript.

Let’s consider an example of a constructor function Tax. An accounting program can create multiple instances if Tax - one per person. Say this program will be used in a Florida neighborhood with predominantly Spanish speaking people. The following code illustrates the case when the method doTax() can be called with or without parameters.

function Tax(income, dependents){
    this.income=income;              // instance variable
    this.dependents=dependents;      // instance variable

    this.doTax = function calcTax(state, language){
           if(!(state && language)){     // 1
              console.log("Income: " + this.income + " Dependents: "+ this.dependents
              + " State: " + Tax.defaults.state + " language:" + Tax.defaults.language);
           } else{                       // 2
              console.log("Income: " + this.income + " Dependents: "+ this.dependents
              + " State: " + state + " language:" + language);
           }
    }
}

Tax.defaults={                           // 3
     state:"FL",
     language:"Spanish"
};

// Creating 2 Tax objects
var t1 = new Tax(50000, 3);
    t1.doTax();                          // 4
var t2 = new Tax(68000, 1);
    t2.doTax("NY","English");            // 5
1 No state and language were given to the method doTax()
2 The state and language were provided as doTax() parameters
3 Assigning the object with two properties as a defaults property on Tax. The property default is not instance specific, which makes it static.
4 Invoking doTax() without parameters - use defaults
5 Invoking doTax() with parameters

This program will produce the following output:

Income: 50000 Dependents: 3 State: FL language:Spanish
Income: 68000 Dependents: 1 State: NY language:English

You can add as many properties to the constructor function as needed. For example, to count the number of instances of the Tax object just add one more property Tax.counter=0;. Now add to the Tax function something like console.log(Tax.counter++); and you’ll see that the counter increments on each instance creation.

Tip If multiple instances of a function object need to access certain HTML elements of the DOM, add references to these elements as function properties so objects can reuse them instead of traversing the DOM (it’s slow) from each instance.

Closures

Imagine a function that contains a private variable, and a nested function. Is it possible to invoke the nested function from the outside of the outer one? And if it’s possible, what this inner function knows about its surroundings?

Larry Ullman, a Web developer and computer books author offers the following definition: "Closure is a function call with memory". We can offer you our version: "Closure is a function call with strings attached". Now it’s turn for the explanation of these mysterious definitions, and we’ll do it by example. Consider the following code that is yet another example of implementing tax collection functionality.

(function (){                // this is an anonymous function expression

    var taxDeduction = 500;  // private context to remember

      //exposed closure
      this.doTaxes=function(income, customerName) {

        var yourTax;

        if (customerName != "Tony Soprano"){
          yourTax =   income*0.05 - taxDeduction;
        } else{
          yourTax =   mafiaSpecial(income);
        }

         console.log( "   Dear " + customerName + ", your tax is "+ yourTax);
         return yourTax;
      }

      //private function
      function mafiaSpecial(income){
          return income*0.05 - taxDeduction*2;
      }

})();    // Self-invoked function

// The closure remembers its context with taxDeduction=500
doTaxes(100000, "John Smith");
doTaxes(100000, "Tony Soprano");

mafiaSpecial();        // throws an error - this function is private

First, a self-invoking function will create an anonymous instance of an object in the global scope. It contains a private variable taxDeduction, a public method doTaxes(), and a private method mafiaSpecial(). Just by the virtue of declaring doTaxes on this object, this method becomes exposed to the current scope, which is global in this example.

After that we call the method doTaxes() twice. Note that the function doTaxes() uses the variable taxDeduction that was never declared there. But when doTaxes was initially declared, the variable taxDeduction with a value of 500 was already there. So the internal function "remembers" the context (the neighborhood) where it was declared and can use it for its calculations.

The algorithm of tax calculations makes doTaxes() calls the function mafiaSpecial() if the customer’s name is "Tony Soprano". The function mafiaSpecial() is not visible from outside, but for insiders like doTaxes() it’s available. Here’s what the above code example will print on the console:

Dear John Smith, your tax is 4500
Dear Tony Soprano, your tax is 4000
Uncaught ReferenceError: mafiaSpecial is not defined

The [FIG2-18] shows the screenshot taken when doTaxes() hit the breakpoint inside doTaxes - note the right panel that shows what’s visible in the Closure scope.

images/fig_02_18.jpg
Figure 18. Closure view in Chrome’s Developer Tools.
Tip JavaScript doesn’t give you an explicit way to mark an variable as private. By using closures you can get the same level of data hiding that you get from private variables in other languages. In the example above the variable taxDeduction is local for the object enclosed in the outermost parentheses and can’t be accessed from outside. But taxDeduction can be visible from the object’s functions doTaxws and mafiaSpecial.

[FIG2-19] gives yet another visual representation of our above code sample. The self-invoked anonymous function is shown as a cloud that exposes only one thing to the rest of the world: the closure doTaxes.

images/fig_02_19.jpg
Figure 19. Closure doTaxes

Let’s consider a couple of more cases of returning a closure to the outside world so it can be invoked later. If the previous code sample was exposing the closure by using this.taxes notation, the next two examples will simply return the code of the closure using the return statement. The code below declares a constructor function Person, adds a function doTaxes() to its prototype, and finally creates two instances of the Person calling the method doTaxes() on each of them.

// Constructor function
function Person(name){

        this.name = name;

}

// Declaring a method that returns closure
Person.prototype.doTaxes= function(){

    var taxDeduction = 500;

      //private function
      function mafiaSpecial(income){
          return income*0.05 - taxDeduction*2;
      }

      //the code of this function is returned to the caller
      return function(income) {

        var yourTax;

        if (this.name != "Tony Soprano"){
          yourTax =   income*0.05 - taxDeduction;
        } else{
          yourTax =   mafiaSpecial(income);
        }

         console.log( "My dear " + this.name + ", your tax is "+ yourTax);
         return yourTax;
      }
}();     // important parentheses!

//Using closure
var p1 = new Person("John Smith");
var result1 = p1.doTaxes(100000);

var p2 = new Person("Tony Soprano");
var result2 = p2.doTaxes(100000);

The calculated taxes in this example are the same as in the previous one: John Smith has to pay $4500, while Tony Soprano only $4000. But we used different technique for exposing the closure. We want to make sure that you didn’t overlooked the parentheses at the very end of the function expression for doTaxes. These parenthesis force the anonymous function to self-invoke itself, it’ll run into a return statement and will assign the code of the anonymous inner function that takes parameter income to the property doTaxes. So when the line var result1 = p1.doTaxes(100000); calls the closure the variable result1 will have the value 4500. Remove these important parentheses, and the value of result1 is not the tax amount, but the the code of the closure itself - the invocation of the closure is not happening.

The following code fragment is yet another example of returning the closure that remembers its context.First, the closure is returned to the caller of prepareTaxes(), and when the closure will be invoked it’ll remember the values defined in its outer context. After looking at this code you can say that there is nothing declared in the closure’s outside context! There is - by the time when the closure is created the value of the studentDeductionAmount will be known.

function prepareTaxes(studentDeductionAmount) {

        return function (income) {           // 1
           return income*0.05 - studentDeductionAmount;
        };

}

var doTaxes = prepareTaxes(300);         // 2
var yourTaxIs = doTaxes(10000);          // 3
console.log("You tax is " + yourTaxIs);  // 4
1 When the function prepareTaxes is called, it immediately hits the return statement and returns the code of the closure to the caller.
2 After this line is executed, the variable doTaxes has the code of the closure, which remembers that studentDeductionAmount is equal to 300.
3 This is actual invocation of the closure
4 the console output is "your tax is 200"
Tip Check the quality of your code with the help of the JavaScript code quality tool JSLint.

Closures as callbacks

Let’s revisit the code from the section Callbacks above. That code has shown how to pass an arbitrary function to another one and invoke it there using call(). But if that version of the function taxHandler was not aware of the context it was created in, the version below will. If in classical object-oriented languages you’d need to pass a method that knows about it’s context, you’d need to create an instance of an object that contains the method and the required object-level properties, and then you’d be passing this wrapper-object to another object for processing. But since the closure remembers its context anyway, we can just pass a closure instead of object. Compare the code below with the code from the Callbacks section.

var myTaxObject = {

    // this function takes an array and callback as parameters
    applyDeduction: function(someArray, someCallBackFunction){

        for (var i = 0; i < someArray.length; i++){

            // Invoke the callback
           someCallBackFunction.call(this, someArray[i]);
        }

    }
}

// array
var preliminaryTaxes=[1000, 2000, 3000];


var taxHandler = function (taxDeduction){

// tax handler closure
        return function(currentTax){
                   console.log("Hello from callback. Your final tax is " +
                   (currentTax - taxDeduction));
                };
}


// invoking applyDeduction passing an array and callback-closure
myTaxObject.applyDeduction(preliminaryTaxes, taxHandler(200));

The last line of the above example calls taxHandler(200), which creates a closure that’s being passed as a callback to the method applyDeduction(). Even though this closure is executed in the context of myTaxObject, it remembers that tax deduction is 200.

Mixins

The need to extend capabilities of objects can be fulfilled by inheritance, but this is not the only way of adding behavior to objects. In this section you’ll see an example of something that would not be possible in the object-oriented languages like Java or C#, which don’t support multiple inheritance. JavaScript allows taking a piece of code and mix it into any object regardless of what its inheritance chain is. Mixin is a code fragment that an object can borrow if need be.

// Defining a function expession
var Tax = function(income, state){
        this.income=income;
        this.state=state;

        this.calcTax=function(){
                var tax=income*0.05;
                console.log("Your calculated tax is " + tax)
                return tax;
        }
};


// Defining a mixin
var TaxMixin = function () {};

TaxMixin.prototype = {

  mafiaSpecial: function(originalTax){
    console.log("Mafia special:" + (originalTax - 1000));
  },

  drugCartelSpecial: function(originalTax){
     console.log("Drug Cartel special:" + (originalTax - 3000));
  }

};

// this function can blend TaxMixin into tax
function blend( mainDish, spices ) {

  for ( var methodName in spices.prototype ) {
      mainDish.prototype[methodName] = spices.prototype[methodName];
  }
}

// Blend the spices with the main dish
blend( Tax, TaxMixin );

// Create an instant of Tax
var t = new Tax(50000, "NY");

var rawTax = t.calcTax();

// invoke a freshly blended method
t.mafiaSpecial(rawTax);

The function blend() loops through the code of the TaxMixin and copies all its properties into Tax. Mixins can be useful is you want to provide a specific feature to a number of different object without changing their inheritance. The other use case is if you want to prepare a bunch of small code fragments (spices) and add any combination of them to the various objects (dishes) as needed. Mixins give you a lot of flexibility in what you can achieve with the minimum code, but they may decrease the readability of your code.

If you’ve read this far, you should have a good understanding of the syntax of the JavaScript language.Studying the code samples provided in this chapter has one extra benefit: now you can apply for a job as a tax accountant in a mafia near you.

JavaScript in the Web Browser

After learning all these facts and techniques about the language you might be eager to see "the real-world use of JavaScript". Slowly but surely a Web browser becomes the leading platform for development of the user interface. The vast majority today’s JavaScript programs primarily manipulate HTML elements of Web pages. In this section we’ll be doing exactly this – applying JavaScript code to modify the content or style of HTML elements.

DOM stands for Document Object Model. It’s an object representing the hierarchy of HTML elements of a Web page. Every element of the HTML document is loaded into DOM. Each DOM element has a reference to its children and siblings. When DOM was invented, the Web pages were simple and static. DOM was not meant to be an object actively accessed by the code. This is the reason that on some of the heavily populated Web pages manipulating of DOM elements can be slow. Most likely DOM is the main target for anyone who’s trying to optimize the performance of a Web page.

Tip If your Web page is slow, analyze it with YSlow, the tool built based on the Yahoo! rules for high performance Web sites. Also, you can minimize and obfuscate your JavaScript code with the help of JavaScript Compressor.

When a Web Browser is receiving the content it keeps performing the following activities:

  • Adding arriving HTML elements to DOM and laying out the content of the Web pages

  • Rendering of the UI

  • Running JavaScript that was included in the HTML

  • Processing events

The amount of time spent on each of these activities varies depending the content of the page.

Tip If you are interested in learning how the browsers work in detail, read an excellent writeup titled "How Browsers Work: Behind The Scenes of Modern Web Browsers" at http://bit.ly/how-browsers-work [http://bit.ly/how-browsers-work].

Let’s consider the operations your application needs to be able to perform inside the Web page:

  • Programmatically finding the required element by id, type, or a CSS class

  • Changing styles of the elements (show, hide, apply fonts and colors et al.)

  • Processing events that may happen to HTML elements (click, mouseover and the like)

  • Dynamically adding or removing HTML elements from the page or changing their contents

  • Communicating with the server side, e.g. submitting forms or making AJAX requests for some data from the server

Now you’ll see some code samples illustrating the use of JavaScript for the listed above operations. Even if you’ll be using one of the popular JavaScript frameworks, your program will be performing similar operations applying the syntax prescribed by your framework of choice. So let’s learn how it can be done.

Working with DOM

If you want to change the appearance of an HTML page, you need to manipulate with the DOM elements. Older Web applications were preparing the HTML content on the server side. For example, a server-side Java servlet would compose and send to the client HTML whenever the application logic required to change the appearance of the UI. The current trend is different - the client’s code takes care of the UI rendering, and only the data go back and forth between the client and the server. You’ll see how this works in more detail in Chapter 4 that explains the use of AJAX and JSON.

Earlier in this chapter we were talking about the global namespace where all JavaScript objects live unless they were declared with var inside the functions. If the JavaScript code is running in a Web browser, this global namespace is represented by a special variable window. It’s an implicit variable and you don’t have to use it in your code, but whenever we say that a variable is global, we mean that it’s exists on the window object. For example, the code below will print "123 Main Street" twice:

var address ="123 Main Street";

console.log(address);
console.log(window.address);

The window object has a number of useful properties like cookie, location, parent, document and others. The variable document points at the root of the DOM hierarchy. Pretty often your JavaScript code would find an element in the DOM first, and then it could read or modify its content. [FIG2-20] is a snapshot from Firebug showing the fragment of a DOM of a simple Web page mixins.html.

images/fig_02_20.jpg
Figure 20. Firebug’s representation of DOM
Single Page Applications

Have you ever seen a monitor of a trader working for a Wall Street firm? Actually, they usually have three or four large monitors, but let’s just look at one of them. Imagine a busy screen with lots and lots constantly changing data grouped in dedicated areas of the window. This screen shows the constantly changing prices from financial markets, the trader can place orders to buy or sell products, and notifications on completed trades are also coming to the same screen. If this is would be a Web application it would live in the same Web page. No menus to open another windows.

The price of Apple share was $590.45 just a second ago and now it’s $590.60. How can this be done technically? Here’s one of the possibilities: every second an AJAX is being made to the remote server providing current stock prices and the JavaScript code finds in the DOM the HTML element responsible for rendering the price and then modifies its value with the latest price.

Have you seen a Web page showing an input box of Google’s Gmail? It looks like a table with a list of rows representing the sender, subject, and the date of when each email arrived. All of a sudden you see a new row in bold on top of the list - the new email came in. How was this done technically? A new object(s) was created and inserted into a DOM tree. No page changes, no needs for the user to refresh the browser’s page - an undercover AJAX call gets the data and JavaScript changes the DOM. The content of DOM changed - the user sees an updated value.

Below are some of the methods that exist on the `document` object:

document.write(text) – adds the specifies text to the DOM. Careless using of the method write() can result in unpredictable results if after changing the DOM the HTML content is still arriving.

document.getElementById(id) – get a reference to the HTML element by its unique identifier

document.getElementsByTagName(tname) - get a reference to one or more elements by tag names, e.g.get a reference to all <div> elements.

document.getElementsByName(name) - get a reference to all elements that have requested value in their name attribute.

document.getElementsByClassName(className) – get a reference to all elements to use specified CSS class.

document.querySelector(cssSelector) – Find the first element that matches provided CSS selector. string.

document.querySelectorAll(cssSelector) – Find all elements that match provided CSS selector string.

The next code sample contains the HTML <span> element that has an id emp. Initially it contains ellipsis, but when the user enters the name in the input text field, the JavaScript code will find the reference to this <span> element and will replace the ellipsis with the content of the input text field.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

        <body>
        <h2>Selecting DOM elements</h2>

        <p>
                The employee of the month is <span id="emp">...</span>
        <br>
        <input type="button" value="Change the span value"
               onclick="setEmployeeOfTheMonth()"/>
        Enter your name  <input type="text" id="theName" />
        </p>

        <script>
           function setEmployeeOfTheMonth(){

                   var mySpan = document.getElementById("emp");

                   var empName= document.getElementsByTagName("input")[1];

                   mySpan.firstChild.nodeValue= empName.value;

                }
        </script>

        </body>
</html>

Note the input field of type button, which includes the onclick property that corresponds to the click event. When the user clicks on the button, the browser dispatched click event, and calls the JavaScript function setEmployeeOfTheMonth(). The latter queries the DOM and finds the reference to the emp by calling the method getElementBuId(). After that, the method getElementByTagName() is called trying to find all the references to the HTML <input> elements. This methods returns an array cause there could be more than one element with the same tag name on a page, which explains the use of array notation. The first <input> element is a button and the second is the text field we’re interested in. Remember that arrays in JavaScript have zero-based indexes. [FIG2-21] shows the Web page after the user entered the name Mary and pressed the button.

images/fig_02_21.jpg
Figure 21. Changing the content of the HTML <span> element

While manipulating the content of your Web page you may you may need to traverse the DOM tree. The code example below shows you an HTML document that includes JavaScript that walks the DOM and prints the name of each node. If a node has children, the recursive function walkTheDOM() will visit each child.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

    <body>
     <h1>WalkTheDom.html</h1>

     <p>
        Enter your name: <input type="text"
                                name="customerName" id="custName" />
     </p>

     <input type="button" value="Walk the DOM"
                          onclick="walkTheDOM(document.body, processNode)"/>

     <script>
                function walkTheDOM(node, processNode){

                   processNode(node)
                    node = node.firstChild;

                              while(node){
                                 // call wakTheDOM recursively for each child
                                 walkTheDOM(node,processNode);
                                 node = node.nextSibling;
                              }
            }

         function processNode(node){
            // the real code for node processing goes here

                console.log("The current node name is "+  node.nodeName);
         }
      </script>
    </body>
</html>

Our function processNode() just prints the name of the current node, but you could implement any code that your Web application requires. Run this code in different browsers and check the output on the JavaScript console. [FIG2-22] depicts two snapshots taken in the F12 Developer Tools in Internet Explorer (left) and FIrebug running in Firefox (right).

images/fig_02_22.jpg
Figure 22. Traversing the DOM in Firefox

While some of the output is self-explanatory, there is a number of #text nodes that you won’t find in the code sample above. Unfortunately, Web browsers treat whitespaces differently, and inserts different number of text nodes in the DOM representing whitespaces found in the HTML document. So you’ll be better off using one of the JavaScript frameworks for traversing the DOM cross-browser way. For example, JQuery framework’s API for DOM traversing is listed at http://bit.ly/WXj2r2.

Styling Web Pages with CSS

CSS stands for Cascading Style Sheets. During the last 15 years several CSS specifications reached the level of Recommendation by W3C: CSS Level 1, 2, and 2.1. The latest CSS Level 3 (a.k.a. CSS3) adds new features to CSS 2.1 module by module, which are listed at http://www.w3.org/Style/CSS/current-work.

Tip You can find CSS tutorial as well as tons of other learning resources at webplatform.org.

You can include CSS into a Web page either by linking to separate files using the HTML tag <link> or by in-lining the styles with the tag <style>. For example, if CSS is located in the file mystyles.css in the folder css add the following tag to HTML:

<link rel="stylesheet" type="text/css" href="css/mystyles.css" media="all">

The <link> tag allows specifying the media where specific css file has to be used. For example, you can have one CSS file for smartphones and another one for tablets. We’ll discuss this in detail in the section on media queries in Chapter 11.

You should put this tag in the section of your HTML before any JavaScript code to make sure that they stiles are loaded before the content of the Web page.

Placing the @import attribute inside the <style> tag allows to include styles located elsewhere:

<style>
   @import url (css/contactus.css)
</style>

What’s the best way of including CSS in HTML? Keeping CSS in multiple files separately from HTML and JavaScript makes the code more readable and reusable. On the other hand, if your Web site has consists of many files, the Web browser will have to make multiple round trips to your server just to load all resources required by the HTML document, which can worsen the responsiveness of your Web application.

HTML documents are often prettyfied by using CSS class selectors, and you can switch them programmatically with JavaScript. Imagine that a <style> section has the following definition of two class selectors badStyle and niceStile:

   <style>
         .badStyle{
        font-family: Verdana;
        font-size:small;
        color:navy;
        background-color:red;
    }

    .niceStyle{
        font-family: Verdana;
        font-size:large;
        font-style:italic;
        color:gray;
        background-color:green;
    }
  </style>

Any of these class selectors can be used by one or more HTML elements, for example

<div id="header" class="badStyle">
   <h1>This is my header</h1>
</div>

Imagine that some important event has happened and the appearance the <div> styled as badStyle should programmatically change to <niceStyle>. In this case we need to find the badStyle element(s) first and change their style. The method getElementsByClassName() returns a set of elements that have the specified class name, and since our HTML has only one such element, the JavaScript will use the element zero from such set:

          document.getElementsByClassName("badStyle")[0].className="niceStyle";

The next example will illustrate adding a new element to the DOM. On click of a button the code below dynamically creates an instance of type img and then assigns the location of the image to its src element. In a similar way we could have assigned values to any other attributes of the img element like width, height, or alt. The method appendChild() is applied to the <body> container, but it could be any other container that exists on the DOM.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

    <body>
     <h2>Employee of the month</h2>
        <p>
             <input type="button" value="Show me"
                    onclick="setEmployeeOfTheMonth()"/>
        </p>

     <script>

         function setEmployeeOfTheMonth(){

           // Create an image and add it to the <body> element
           var empImage=document.createElement("img");
                   empImage.setAttribute('src','resources/images/employee.jpg');
                   document.body.appendChild(empImage);
                }

     </script>
    </body>
</html>
Tip Some HTML elements like <div> or <span> have contain other elements (children), and if you need to change their content use their property innerHTML. For example, to delete the entire content of the document body just do this: document.body.innerHTML="".

If you run this example and click on the button "Show me" you’ll see an image of the employee of the month added to the <body> section of the HTML document as shown on [FIG2-23].

images/fig_02_23.jpg
Figure 23. After clicking the button "Show me"

DOM Events

Web browser will notify your application when some changes or interactions occur. In such cases the browser will dispatch an appropriate event, for example load, unload, mousemove, click, keydown etc. When the Web page finished loading the browser will dispatch the load event. When the user will click on the button on a Web page the click event will be dispatched. A Web developer needs to provide JavaScript code that will react on the events important to the application. The browser events will occur regardless of if you provided the code to handle them or not. It’s important to understand some terms related to event processing.

An event handler (a.k.a. event listener) is a JavaScript code you want to be called as a response to this event. The last code sample from the previous section was processing the click event on the button "Show me" as follows: onclick="setEmployeeOfTheMonth()".

Tip Each HTML element has a certain number of predefined event attributes, which start with the prefix on followed by the name of the event. For example onclick is an event attribute that you can use for specifying the handler for the click event. You can find out what event attributes are available in the online document titled Document Object Model Events.

The preferred way of adding event listener was introduced in the DOM Level 2 specification back in 2000. You should find the HTML element in the DOM, and then assign the event listener to it by calling the method addEventListener(). For example:

document.getElementById("myButton").addEventListener("click", setEmployeeOfTheMonth);

The advantage of using of such programmatic assignment of event listeners is that this can be done for all controls in a in a central place, for example in a JavaScript function that runs immediately after the Web page completes loading. Another advantage is that you can programmatically remove the event listener if it’s not needed any longer by invoking removeEventListener(). The following example is a re-write of the last example from the previous section.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

    <body>
     <h2>Employee of the month</h2>
        <p>
             <input type="button" value="Show me" id="myButton"/> <!-- 1 -->
        </p>

     <script>
         window.onload=function(){         // 2
                document.getElementById("myButton").addEventListener("click",
                                                      setEmployeeOfTheMonth);
         }

         function setEmployeeOfTheMonth(){

           // Create an image and add it to the <body> element
           var empImage=document.createElement("img");
                   empImage.setAttribute('src','resources/images/employee.jpg');
                   document.body.appendChild(empImage);

                 document.getElementById("myButton").removeEventListener("click",
                                                 setEmployeeOfTheMonth); // 3
                }

     </script>
    </body>
</html>
1 Compare this button with the one from the previous section: the event handler is removed, but it has an ID now.
2 When the Web page completes loading, a load event is dispatched and the function attached to the event attribute onload assigns the event handler for the button click event. Note that we are passing the callback setEmployeeOfTheMonth as the second argument of the addEventListener()
3 Removing the event listener after the image of the employee of the month has been added. Without this line each click on the button would add to the Web page yet another copy of the same image.

Each event goes through three different phases: Capture, Target, and Bubble. It’s easier to explain this concept by example. Imagine that a button is located inside the <div>, which is located inside the <body> container. When you click on the button, the event travels to the button through all enclosing containers, and this is the capture phase. You can intercept the event at one of these containers even before it reached the button if need be. For example, your application logic may need to prevent the button from being clicked if certain condition occurs.

Then event reaches the button, and it’s a target phase. After the event is handled by the button’s click handler, the event bubbles up through the enclosing containers, and this is the bubble phase. you can create listeners and handle this event after the button finished its processing at the target phase. The next code sample is based on the previous one, but it demonstrates the event processing in all three phases.

Note that if your event handler function is declared with the event parameter, it’ll receive the Event object, which contains a number of useful parameters. For more information refer to the "Document Object Model Events" online.

<!DOCTYPE html>
<html>
        <head>
                <meta charset="utf-8" />
        </head>

    <body>
     <h2>Employee of the month</h2>
        <div id="myDiv">
             <input type="button" value="Show me" id="myButton"/>
        </div>

     <script>
         window.onload=function(){
                document.getElementById("myButton").addEventListener("click",
                                                          setEmployeeOfTheMonth);

                document.getElementById("myDiv").addEventListener("click",
                                                          processDivBefore, true); // 1
                document.getElementById("myButton").addEventListener("click",
                                                          processDivAfter);

         }

         function setEmployeeOfTheMonth(){

           console.log("Got the click event in target phase");

           // Create an image and add it to the <body> element
           var empImage=document.createElement("img");
                   empImage.setAttribute('src','resources/images/employee.jpg');
                   document.body.appendChild(empImage);

                 document.getElementById("myButton").removeEventListener("click",
                                                              setEmployeeOfTheMonth);
                }

         function processDivBefore(evt){
                console.log("Intercepted the click event in capture phase");

                // Cancel the click event so the button won't get it

                // if (evt.preventDefault) evt.preventDefault();        2
                // if (evt.stopPropagation) evt.stopPropagation();
         }

         function processDivAfter(){
                console.log("Got the click event in bubble phase");
         }
     </script>
    </body>
</html>
1 We’ve added two event handler on the <div> level. The first one intercepts the event on the capture phase. When the third argument of addEventListener() is true, this handler will kick in during capture phase.
2 If you uncomment these two lines, the default behavior if the click event will be cancelled and it won’t reach the button at all. Unfortunately, browsers may have different method implementing prevent default functionality hence additional if-statements are needed.

Running the above example will cause the following output in the JavaScript console:

Intercepted the click event in capture phase
Got the click event in target phase
Got the click event in bubble phase

You can see another example of using intercepting the event during the capture phase in the Donate Section of Chapter 2.

Tip The Microsoft’s Web browsers Internet Explorer 8 and below didn’t implement the W3C DOM Level 3 event model - they handled events differently. You can read more on the subject at this MSDN article http://bit.ly/anZZgZ.

Summary

This chapter was covering the JavaScript language constructs that any professional Web developer should know. A smaller portion of this chapter was illustrating how to combine JavaScript, HTML, and CSS. There are lots of online resources and books that cover just the HTML markup and CSS, and you’ll definitely need to spend more time mastering details of the Web tools like Firebug or Google Developer Tools. Starting from the next chapter we’ll be working on the Save Sick Child application, which will help you in better understanding of how these ingredients of HTML5 work together and compliment each other.

Mocking Up the Application «Save Sick Child»

The time has come to start working on our Web application Save Sick Child. It’s going to be a Web application that will supports donations to sick children, show some video, integrate the Google maps, and will feature an online auction. The goal is to gradually build all the functionality of the Web site while explaining each step of the way and giving you the reasons why we are building it the way we do. By the end of this chapter the Web design and the first prototype of the Save Sick Child will be ready.

The proliferation of mobile devices and Web applications require new skills for development of what was known as boring-looking enterprise applications. In the past, design of the user interface of most of the enterprise applications was done by developers to the best of their artistic abilities: a couple of buttons here, and a grid there on a gray background. The business users were happy cause they did not see any better. The application allowed to process business data – what else to wish for? Enterprise business users used to be happy with any UI as long as the application helped them to take care of their business.

But today’s business users are spoiled by nice looking consumers applications, and more often than not new development starts with inviting a Web designer who should create a prototype of the future application. For example, we’ve seen some excellent (from the UI perspective) functional specifications for boring financial applications made by professional designers. Business users slowly but surely becoming more demanding in the area of the UI design solutions. The trend is clear: developer’s art does not cut it anymore. You need to hire a professional Web designer for your next Web application. The software developers are not overly familiar with the tools that Web designers are using. This chapter will illustrate the process of design and prototyping of the UI of a Web application.

Our Web designer, let’s call him Jerry, is ready to start working on the mockup (a.k.a. wireframes) - a set of images depicting various views of the future Save Sick Child application. We expect him to deliver images with comments that would briefly explain what should change in a view if a user will take certain actions, e.g. clicks on the button. You can also think of a UI of an application as a set of states, and the user’s action result in your application transitioning from one state to the other. As nerds and mathematicians say, the UI of your application is a finite state machine", which at any given point of time is in one of the finite number of states, for example, in the view state Donate Form or Auction.

Mobile First?

While starting working on the design of a new Web application keep in mind that most likely some users will access it from mobile devices. Will the proposed UI look good on the mobile devices with smaller screens? Some people suggest using so-called "Mobile First" approach. For example, take the geographical location services. The users of iOS and Android devices are used to the fact that they can find the closest restaurant or a gas station based on their current location. Do you know that location feature can be available on the desktops too? Google maps API is just one of the services that can find the location of the user’s desktop based on its IP address, Wi-Fi router’s ID or proximity to the cell towers.Zeroing in on your device may not be as precise as with the smartphone’s GPS, but it may be good enough. So why not plan for adding this feature to all versions of your Web application? Finding the closest charity event or a sick sick child can be done knowing an approximate location of your desktop computer.

Let’s consider pointing devices. At the time of this writing, vast majority of the desktop users work with pixel-perfect mouse pointers or track pads. SmartPhone or tablet users work with fingers. One finger touch can cover a square with 100 pixels. The CNN site shows lots of news links located very close to each other on the screen. A finger may cover more than one link, and Android devices offer you a larger popup allowing you to select the link you really wanted to touch. Having the "Mobile first" state of mind doesn’t mean that CNN would need to keep the larger distance between the links for all the users. But this means that they should foresee the issues or innovate using the features offered by modern mobile devices.

In Chapter 11 we’ll discuss the responsive design techniques that allow to create the UI for Web applications that automatically re-allocate the screen content based on the screen size of the user’s device. Although this chapter is about the desktop version of the Sick Child Web application, its screen will consist of several rectangular areas that can be allocated differently (or even hidden) on smartphones or tablets.

One of the constraints that the mobile users have is the relatively slow speed of the mobile Internet. This means that even though your desktop users will use fast LAN connection lines, your Web application has to be modularized and only the minimal number modules has to be loaded initially. Often mobile providers charge the user based on the amount of consumed data too.

The chances are slim that the desktop users will lose the Internet connection for a long period of time. On the other hand, the mobile users may stay in the area with no or spotty connection. In this case the "Mobile First" thinking can lead to introducing an offline mode with limited functionality.

Thinking upfront of the minimal content to be displayed on a small mobile screens may force you to change the design of the desktop Web pages too. In our sample Save Sick Child application we need to make sure that there is a space for the Donate button even on the smallest devices.

Introducing Balsamiq Mockups

Visualize a project owner talking to Jerry in a cafeteria, and Jerry is drawing sketches of the future Web site on a napkin. Well, in the 21st Century he’ll use an electronic napkin so to speak - an excellent prototyping tool called Balsamiq Mockups. This easy to use program gives you a working area where you create a mockup of your future Web application by dragging and dropping the required UI components from the toolbar onto the image of the Web page (see [FIG3-1]).

image
Figure 24. The working area of Balsamiq Mockups
Tip If you can’t find the required image in Balsamiq’s library, add your own by dragging and dropping it onto the top toolbar. For example, the mockup in Chapter 11 uses our images of the iPhone that we’ve added to Balsamiq assets.

When the prototype is done, it can be saved as an image and sent to the project owner. Another option is to export the Balsamiq project into XML, and if both the project owner and Web designer have Balsamiq installed, they can work on the prototype in collaboration. For example, the designer exports the current states of the project, the owner imports it and makes corrections or comments, then exports it again and sends it back to the designer.

The Project Owner Talks to a Web Designer

During the first meeting Jerry talks to the project owner discussing the required functionality and then creates the UI to be implemented by Web developers. The artifacts produced by the designer vary depending on the qualifications of the designer. This can be a set of images representing different states of the UI with little callouts explaining the navigation of the application. If the Web designer is familiar with HTML and CSS, developers may get a working prototype in the form of HTML and CSS files, and this is exactly what Jerry will create by the end of this chapter.

Our project owner said to Jerry: "The Save Sick Child Web site should allow people to make donations to sick children. The users should be able to find these children by specifying a geographical area on the map. The site should be integrated with a payment system, include a video player and display statistics about the donors and recipients. The site should include an online auction with proceeds going to charity. We’ll start working on the desktop version of this site first, but your future mockup should include three versions of the UI supporting desktops, tablets, and smartphones".

After the meeting Jerry launched Balsamiq and started to work. He decided that the main window will consist of four areas laid out vertically:

  1. The header with the logo and several navigation buttons

  2. The main area with the Donate support plus the video player

  3. The area with the Find Local Kid, statistics, and charts.

  4. The footer with several house-holding links plus the icons for Twitter and FaceBook.

First Mockups

The first deliverable of our Web designer (see [FIG3-2] and [FIG3-3]) depicted two states of the UI: before and after clicking the button Donate Now. The Web designer suggested that on the button click the Video Player would turn into a small button revealing the donation form.

images/fig_03_02.png
Figure 25. The main view before clicking Donate Now
images/fig_03_03.png
Figure 26. The main view after clicking Donate Now

The project owner suggested that turning the video into a Donate button may not be a the best idea. We shouldn’t forget that the main goal of this application is collecting donation, so they decided to keep the user’s attention on the Donate area and move the video player to the lower portion of the window.

After that they went over the mockups of the authorization routine. The view states in this process can be : 1. Not Logged On 2. The Login Form 3. Wrong ID/Password 4. Forgot Password 5. Successfully Logged On

The Web designer has created mockups of some of these states as shown on [FIG3-4] and [FIG3-5].

images/fig_03_04.png
Figure 27. The user haven’t clicked on the Login button

The latter shows different UI states should the user decide to log in. The project owner reviewed the mokups and return them back to Jerry with some comments. The project owner wanted to make sure that the user doesn’t have to log on to the application to access the Web site. The process of making donations has to be as easy as possible, and forcing the donor to log on may scare some people away, so the project owner left his comment as shown on [FIG3-5].

images/fig_03_05.png
Figure 28. The user haven’t clicked on the Login button

From Mockups to a Prototype

We are lucky - Jerry knows HTML and CSS. He’s ready to turn the still mockups into the first working prototype. It’ll use only hard-coded data but the layout of the site will be done in CSS and we’ll use HTML5 markup.

Note Authors of this book assume that the users of our "Save Sick Child" site work with the modern versions of Web browsers (two year old or younger). The real world Web developers need to deal with finding workarounds to the unsupported CSS or HTML5 features in the old browsers, but modern IDE generate HTML5 boilerplate code that include large CSS files providing different solutions to older browsers. JavaScript frameworks implement workaround for features unsupported by old browsers too, so we don’t want to clutter the text providing several versions of the code just to make book samples work in outdated browsers.

This chapter will include lots of code samples illustrating how the UI is gradually being built. We’ve created a number of Aptana Studio projects and each of them can be run independently. Create a new workspace in Aptana Studio (File | Switch Workspace) and import all these projects from ch3.zip in one shot (File | Import | General | Exiting projects into Workspace ). After that you’ll be able to run each of these examples by right-clicking on the index.html and selecting Run as | JavaScript Web Application.

Basic Page Layout and Login

In this section you’ll see several Aptana projects that show how the static mockup will turn into a working prototype with the help of HTML, CSS, and JavaScript. Jerry, the designer, decided to have four separate areas on the page hence he created the HTML file index.html that has the tag <header> with the navigation tag <nav>, two <div> tags for the middle sections of the page and a <footer>:

<!DOCTYPE html>
<html lang="en">
 <head>
        <meta charset="utf-8">
        <title>Save Sick Child | Home Page</title>
        <link rel="stylesheet" href="css/styles.css">
 </head>
 <body>
        <div id="main-container">
                <header>
                 <h1>Save Sick Child</h1>
                 <nav>
                  <ul>
                        <li>
                          <a href="javascript:void()">Who we are</a>
                        </li>
                        <li>
                          <a href="javascript:void()">What we do</a>
                        </li>
                        <li>
                          <a href="javascript:void()">Way to give</a>
                        </li>
                        <li>
                          <a href="javascript:void()">How we work</a>
                        </li>
                  </ul>
                 </nav>
                </header>
                <div id="main" role="main">
                        <section>
                          Donate section and Video Player go here
                        </section>
                        <section>
                          Locate sick child, stats and tab folder go here
                        </section>
                </div>
                <footer>
                        <section id="temp-project-name-container">
                                <b>project 01</b>: This is the page footer
                        </section>
                </footer>
        </div>
 </body>
</html>

Note that the above HTML includes the CSS file shown below using the <link> tag. Since there is no content yet for the navigation links to open, we use the syntax href="javascript:void() that allows to create a live link that doesn’t load any page, which is fine on the prototyping stage.

/* Navigation menu */
nav {
        float: right
}
nav ul li {
        list-style: none;
        float: left;
}
nav ul li a {
        display: block;
        padding: 7px 12px;
}

/* Main content
 #main-container is a wrapper for all page content
 */
#main-container {
        width: 980px;
        margin: 0 auto;
}
div#main {
        clear: both;
}

/* Footer */
footer {
        /* Set background color just to make the footer standout*/
        background: #eee;
        height: 20px;
}
footer #temp-project-name-container {
        float: left;
}

The above CSS controls not only the styles of the page content, but also that sets the page layout. The <nav> section should be pushed to the right. If an unordered list is placed inside the <nav>, it should be left aligned. The width of the HTML container with ID main-container should be 980 pixels, and it has to be automatically centered. The footer will be 20 pixels high and should have a gray background. The first version of our Web page is shown on [FIG3-6]

Tip In Chapter 11 you’ll see how to create Web pages with more flexible layouts that don’t require specifying absolute sizes in pixels.
images/fig_03_06.png
Figure 29. Working prototype. Take 1: Getting Started.

The next version of our prototype is a lot more interesting and it will contain a lot more code. First of all, the CSS file will become fancier, the layout of the four page sections will properly divide the screen real estate. We’ll add a Logo and a nicely styled Login button to the top of the page. This version of the code will also introduce some JavaScript supporting user’s authorization. Run the Aptana project project-02-login, and you’ll see a window similar to [FIG3-7].

images/fig_03_07.png
Figure 30. Working prototype. Take2: Login.

The new Aptana project created by Jerry has several directories to keep JavaScript, images, CSS, and fonts separately. We’ll talk about special icon fonts later in this section, but first things first - let’s take a close look at the HTML code.

<!DOCTYPE html>
<html lang="en">
 <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title>Save Sick Child</title>
        <link rel="stylesheet" href="assets/css/styles.css">

 </head>
  <body>
        <div id="main-container">
         <header>
<!-- 1 -->
          <h1 id="logo"><a href="javascript:void(0)">Save Sick Child</a></h1>

           <nav id="top-nav">
                <ul>
                  <li id="login">
                   <div id="authorized">
                    <span class="icon-user authorized-icon"></span>
                    <span id="user-authorized">admin</span>
                    <br/>
                    <a id="profile-link" href="javascript:void(0);">profile</a> |
                    <a id="logout-link" href="javascript:void(0);">logout</a>
                   </div>

                   <form id="login-form">
                    <span class="icon-user login-form-icons"></span>
                    <input id="username" name="username" type="text"
                                placeholder="username" autocomplete="off" />
                    &nbsp; <span class="icon-locked login-form-icons"></span>
                    <input id="password" name="password"
                                type="password" placeholder="password"/>
                   </form>
                   <a id="login-submit" href="javascript:void(0)">login &nbsp;
                                <span class="icon-enter"></span> </a>

<!-- 2 -->
                        <!-- <a id="login-link" class="show-form"
                                   href="javascript:void(0)">login
                                   &nbsp;<span class="icon-enter"></span> </a> -->

                        <div id="login-link" class="show-form">login
                                      &nbsp; <span class="icon-enter"></span></div>

                        <div class="clearfix"></div>
                 </li>
                 <li id="top-menu-items">
                        <ul>
                                <li>
                                        <a href="javascript:void(0)">Who We Are</a>
                                </li>
                                <li>
                                        <a href="javascript:void(0)">What We Do</a>
                                </li>
                                <li>
                                        <a href="javascript:void(0)">Where We Work</a>
                                </li>
                                <li>
                                        <a href="javascript:void(0)">Way To Give</a>
                                </li>
                        </ul>
                 </li>
                </ul>
           </nav>
         </header>

         <div id="main" role="main">
                <section id="main-top-section">
                        <br/>
                        Main content. Top section.
                </section>
                <section id="main-bottom-section">
                        Main content. Bottom section.
                </section>
         </div>
         <footer>
                <section id="temp-project-name-container">
                        <b>This is the footer</b>
                </section>
         </footer>
        </div>
        <script src="assets/js/main.js"></script>
 </body>
</html>
1 Usually, the logos on multi-page Web sites are clickable - they bring up the home page. That’s why Jerry placed the anchor tag there. But we are planning to build a single-page application (SPA) so having a clickable logo won’t be needed.
2 Run this project in Aptana and click on the button Login, and you’ll see that it reacts. But looking at the login-related <a> tags in the code above you’ll find nothing but href="javascript:void(0)". So why the button reacts? Read the code in the main.js shown below, and you’ll find there line loginLink.addEventListener('click', showLoginForm, false); that invokes the callback showLoginForm(). That why the Login button reacts. This seems confusing cause the anchor component was used here just for styling purposes. In this example a better solution would be to replace the anchor tag <a id="login-link" class="show-form" href="javascript:void(0)"> with another component that doesn’t make the code confusing, for example <div id="login-link" class="show-form">.
Note Single Page Web Applications (SPA) are the ones that don’t require loading multiple pages as a result of the user’s action. The user enters the URL in the browser, which brings the Web page that remains open on the screen until the user stop working with this application. The portion of the user’s screen may change using the AJAX techniques (see Chapter 4), but the page doesn’t gets reloaded. This allows building so-called fat client applications that can remember its state.

Now let’s examine the JavaScript code located in main.js. This code will self-invoke the anonymous function, which creates an object - encapsulated namespace ssc (short for Save Sick Child). This avoids polluting the global namespace. If we wanted to expose anything from this closure to the global namespace we could have done is as described in Chapter 2 in the section Closures, but in our example the code in main.js is completely sealed.

// global namespace ssc
var ssc = (function() {
    // Encapsulated variables

    // Find login section elements                   //  1
        var loginLink = document.getElementById("login-link");
        var loginForm = document.getElementById("login-form");
        var loginSubmit = document.getElementById('login-submit');
        var logoutLink = document.getElementById('logout-link');
        var profileLink = document.getElementById('profile-link');
        var authorizedSection = document.getElementById("authorized");

        var userName = document.getElementById('username');
        var userPassword = document.getElementById('password');

        // Register event listeners                       // 2

        loginLink.addEventListener('click', showLoginForm, false);
        loginSubmit.addEventListener('click', logIn, false);
        logoutLink.addEventListener('click', logOut, false);
        profileLink.addEventListener('click', getProfile, false);

        function showLoginForm() {
                loginLink.style.display = "none";             // 3
                loginForm.style.display = "block";
                loginSubmit.style.display = "block";
        }

        function showAuthorizedSection() {
                authorizedSection.style.display = "block";
                loginForm.style.display = "none";
                loginSubmit.style.display = "none";
        }

        function logIn() {
                //check credentials
                var userNameValue = userName.value;
                var userNameValueLength = userName.value.length;
                var userPasswordValue = userPassword.value;
                var userPasswordLength = userPassword.value.length;

                if (userNameValueLength == 0 || userPasswordLength == 0) {
                        if (userNameValueLength == 0) {
                                console.log("username can't be empty");
                        }
                        if (userPasswordLength == 0) {
                                console.log("password can't be empty");
                        }
                } else if (userNameValue != 'admin' ||
                                          userPasswordValue != '1234') {
                        console.log('username or password is invalid');

                } else if (userNameValue == 'admin' &&
                                          userPasswordValue == '1234') {

                        showAuthorizedSection();                     // 4
                }
        }

        function logOut() {
                userName.value = '';
                userPassword.value = '';
                authorizedSection.style.display = "none";
                loginLink.style.display = "block";
        }

        function getProfile() {
                console.log('Profile link clicked');
        }

})();
1 First query the DOM to get references to login-related HTML elements.
2 Register event listeners for the clickable login elements.
3 To make a DOM element invisible set its style.display="none". Hide the login button and show the login form having two input fields for entering the user id and the password.
4 If the user is admin and the password is 1234, hide the loginForm and make the top corner of the page look as in [FIG3-8]
images/fig_03_08.png
Figure 31. After successful login

In the beginning of Chapter 2 we’ve recommended to put the <script> tag with your JavaScript at the end of your HTML file, which we did in our index.html above. If you move the line <script src="assets/js/main.js"></script> to the top of the <body> section and re-run index.html the screen will look as in [FIG3-7], but clicking on the Login won’t display the login form as it should. Why? Because registering of the event listeners in the script main.js failed cause the DOM components (login-link, login-form and others) were not created yet by the time this script was running. Open the Firebug or other debugging tool and you’ll see an error on the console that will look similar to the following:

"TypeError: loginLink is null loginLink.addEventListener(click, showLoginForm, false);"

Of course, in many cases your JavaScript code could have tested if the DOM elements exist before using them, but in this particular sample it’s just easier to to put the script at the end of the HTML file. Another solution would be to load the JavaScript code located in main.js in a separate handler function that would run only when the window’s load event is dispatched by the browser indicated that the DOM is ready: window.onload = function() {...}. You’ll see how to do this in the next version of main.js.

After reviewing the HTML and JavaScript code let’s spend a little more time with the CSS that supports the pages shown in [FIG3-7]. The difference between the screen shots shown in [FIG3-6] and [FIG3-7] is substantial. First, the top left image is nowere to be found in index.html. Open the styles.css file and you’ll see the line background: url(../img/logo.png) no-repeat; in the header h1#logo section.

The page layout is also specified in the file styles.css. In this version the sizes of each section is specified in pixels (px), which won’t make you page fluid and easily resizable. For example, the HTML element with id="main-top-section" is styled like this:

#main-top-section {
        width: 100%;
        height: 320px;
        margin-top: 18px;
}

Jerry styled the main to section to take the entire width of the browser’s window and to be 320 pixels tall. If you’ll keep in mind the "Mobile First" mantra, this may not be the best approach cause 320 pixels mean difference size (in inches) on the displays with different screen density. For example, 320 pixels on the iPhone 5 with retina display will look a lot smaller than 320 pixels on the iPhone 4. You may consider switching from px to em units: 1em is equal to the current font height, 2em means twice the size et al. You can read more about creating scalable style sheets with em units at http://www.w3.org/WAI/GL/css2em.htm.

What looks a Login button on [FIG3-7] is not a button, but a styled div element. Initially it was a clickable anchor <a>, and we’ve explained this change right after the listing shown index.html above. The CSS fragment supporting the Login button looks like this:

li#login input {
        width: 122px;
        padding: 4px;
        border: 1px solid #ddd;
        border-radius: 2px;
        -moz-border-radius: 2px;
        -webkit-border-radius: 2px;
}

The border-radius element makes the corners rounded of the HTML element it applied to. But why we repeat it three times with additional prefixes -moz- and -webkit-? These are so called CSS vendor prefixes, which allow the Web browser vendors to implement experimental CSS properties that haven’t been standardized yet. For example, -webkit- is the prefix for all WebKit-based browsers: Chrome, Safari, Android, iOS. Microsoft uses -ms- for Internet Explorer, Opera uses -o-. These prefixes are temporary measures, which make the CSS files heavier than they need to be. The time will come when the CSS3 standard properties will be implemented by all browser vendors and you won’t need to use these prefixes.

As a matter of fact, unless yo uwant this code to work in the very old versions of Firefox, you can remove the line -moz-border-radius: 2px; from our styles.css because Mozilla has implemented the property border-radius in most of their browser . You can find a list of CSS properties with the corresponding vendor prefixes in this list maintained by Peter Beverloo.

The footer section comes next. Run the Aptana’s project called project-03-footer and you’ll see a new version of the Save Scick Child page with the bottom portion that looks as in [FIG3-9]. The footer section shows several icons linking to Facebook, Google Plus, Twitter, RSS feed, and e-mail.

images/fig_03_09.png
Figure 32. The footer section

The HTML section of our first prototype is shown below. At this point it has a number of <a> tags, which have the dummy references href="javascript:void(0)" that don’t redirect the user to any of these social sites.

<footer>
 <section id="temp-project-name-container">
        <b>project 03</b>: Footer Section | Using Icon Fonts
 </section>
 <section id="social-icons">
        <a href="javascript:void(0)" title="Our Facebook page">
           <span aria-hidden="true" class="icon-facebook"></span></a>
        <a href="javascript:void(0)" title="Our Google Plus page">
           <span aria-hidden="true" class="icon-gplus"></span></a>
        <a href="javascript:void(0)" title="Our Twitter">
           <span aria-hidden="true" class="icon-twitter"></span></a> &nbsp;
        <a href="javascript:void(0)" title="RSS feed">
           <span aria-hidden="true" class="icon-feed"></span></a>
        <a href="javascript:void(0)" title="Email us">
           <span aria-hidden="true" class="icon-mail"></span></a>
 </section>
</footer>

Each of the above anchors is styled using vector graphics icon fonts that we’ve selected and downloaded from http://icomoon.io/app. Vector graphics images are being re-drawn using vectors (strokes) as opposed to raster graphics, which is are pre-drawn in certain resolution images. The raster graphics can give you these boxy pixelated images if the size of the image needs to be increased. We use the vector images for our footer section that are treated as fonts. They will look as good as originals on any screen size, besides you can change their properties (e.g. color) as easy as you’d do with any other font. The images that you see on [FIG3-9] are are located in the fonts directory of the project-03-footer. The IcoMoon web application will generate the fonts for you based on your selection and you’ll get a sample html file, fonts, and CSS to be used with your application. Our icon fonts section in styles.css will look as follows:

/* Icon Fonts */
@font-face {
        font-family: 'icomoon';
        src:url('../fonts/icomoon.eot');
        src:url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'),
                url('../fonts/icomoon.svg#icomoon') format('svg'),
                url('../fonts/icomoon.woff') format('woff'),
                url('../fonts/icomoon.ttf') format('truetype');
        font-weight: normal;
        font-style: normal;
}

The Donate Section

The section with the Donate button and the donation form will be located in the top portion of page right below the navigation area. Initially, the page will open up with the background image of a sick but smiley boy on the right and a large Donate button on the left. The image shown on [FIG3-10] is taken from a large collection of photos at iStockphoto Web site. We haven’t paid for it just yet hence it shows the iStockPhoto watermark. We are going to purchase this photo as well as the top left logo, to be perfectly legitimate. We’re also using two more background images here: one with the flowers, and the other with the sun and clouds, and you can find the references to these images in the styles.css file. Run the Aptana’s project-04-donation and you’ll see the new version of or Save Sick Child page that will look as on [FIG3-10].

images/fig_03_10.png
Figure 33. The initial view of the Donate section

Lorem Ipsum is a dummy text widely used in printing, typesetting, and Web design. It’s used as a placeholder to indicate the text areas that should be filled with a real content later on. You can read about it at http://www.lipsum.com. This is how the HTML fragment supporting [FIG3-10] looks like (no CSS is shown for brevity).

<div id="donation-address">
        <p class="donation-address">
                Lorem ipsum dolor sit amet, consectetur e magna aliqua.
                Nostrud exercitation ullamco laboris nisi ut aliquip ex
                ea commodo consequat.
                Duis aute irure dolor in reprehenderit in voluptate velit
                esse cillum dolore eu fugiat nulla pariatur.
                Excepteur sint occaecat cupidatat non proident.
        </p>
        <button class="donate-button" id="donate-botton">
                <span class="donate-botton-header">Donate Now</span>
                <br/>
                <span class="donate-2nd-line">Children can't wait</span>
        </button>

</div>

Clicking the button Donate should reveal the form where the user should be able to enter her name, address and the donation amount. We are building a single-page application, so instead of opening a popup window we’ll just change the content on the left revealing the form, and move the button Donate to the right. [FIG3-11] shows how the top portion of our page will look like after the user clicks the Donate button.

images/fig_03_11.png
Figure 34. After clicking on Donate button

The HTML of the donation form shown on [FIG3-11] is shown below. When the user clicks on the Donate button the content of the form should be sent to PayPal or any other payment processing system.

<div id="donate-form-container">
 <h3>Make a donation today</h3>
 <form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">
  <div class="donation-form-section">
        <label class="donation-heading">Please select or enter
                <br/> donation amount</label>
        <input type="radio" name = "amount" id= "d10" value = "10"/>
        <label for = "d10">10</label>
        <br/>
        <input type="radio" name = "amount" id = "d20" value="20" />
        <label for = "d20">20</label>
        <br/>
        <input type="radio" name = "amount" id="d50" checked="checked" value="50" />
        <label for="d50">50</label>
        <br/>
        <input type="radio" name = "amount" id="d100" value="100" />
        <label for="d100">100</label>
        <br/>
        <input type="radio" name = "amount" id="d200" value="200" />
        <label for="d200">200</label>
        <label class="donation-heading">Other amount</label>
        <input id="customAmount" name="amount" value=""
               type="text"  autocomplete="off" />
  </div>
  <div class="donation-form-section">
        <label class="donation-heading">Donor information</label>
        <input type="text" id="full_name" name="full_name"
               placeholder="full name *" required>
        <input type="email" id="email_addr" name="email_addr"
               placeholder="email *" required>
        <input type="text" id="street_address" name="street_address"
               placeholder="address">
        <input type="text" id="city" name="scty" placeholder="city">
        <input type="text" id="zip" name="zip" placeholder="zip/postal code">
        <select name="state">
                <option value="" selected="selected"> - State - </option>
                <option value="AL">Alabama</option>
                <option value="WY">Wyoming</option>
        </select>
        <select name="country">
                <option value="" selected="selected"> - Country - </option>
                <option value="United States">United States</option>
                <option value="Zimbabwe">Zimbabwe</option>
        </select>
  </div>

  <div class="donation-form-section make-payment">
        <h4>We accept Paypal payments</h4>
        <p>
                Your payment will processed securely by <b>PayPal</b>.
                PayPal employ industry-leading encryption and fraud prevention tools.
                Your financial information is never divulged to us.
        </p>

        <button  type="submit" class="donate-button donate-button-submit">
                <span class="donate-botton-header">Donate Now</span>
                <br/>
                <span class="donate-2nd-line">Children can't wait</span>
        </button>
        <a id="donate-later-link" href="javascript:void(0);">I'll donate later
        <span class="icon-cancel"></span></a>
  </div>
 </form>
</div>

The JavaScript code supporting the UI transformations related to the button Donate is shown below. It’s the code snippet from the main.js from Aptana’s project-04-donation. The click on the Donate button invokes the event handler showDonationForm(), which simply hides the <div id="donation-address"> with Lorem Ipsum and displays the donation form: ` <form name="_xclick" action="https://www.paypal.com/cgi-bin/webscr" method="post">">. After clicking on the submit button the data from the form `_xclick will be validated and sent to paypal.com. If the user clicks on "I’ll donate later", the code hides the form and shows the Lorem Ipsum from the <div id="donation-address"> again.

Two select dropdowns in the code above contain hard-coded values of all states and countries. For brevity, we’ve listed just a couple of entries in each. In Chapter 4 we’ll populate these dropdowns using the external data in JSON format.

The next code fragment is an extract of JavaScript file main.js provide by Jerry. This code contains function handlers that process user clicks in the Donate section.

(function() {
        var donateBotton = document.getElementById('donate-botton');
        var donationAddress = document.getElementById('donation-address');
        var customAmount = document.getElementById('customAmount');
        var donateForm = document.forms['_xclick'];
        var donateLaterLink = document.getElementById('donate-later-link');
        var checkedInd = 2;

        function showDonationForm() {
                donationAddress.style.display = "none";
                donateFormContainer.style.display = "block";
        }

    // Register the event listeners
        donateBotton.addEventListener('click', showDonationForm, false);
        customAmount.addEventListener('focus', onCustomAmountFocus, false);
        donateLaterLink.addEventListener('click', donateLater, false);
        customAmount.addEventListener('blur', onCustomAmountBlur, false);

        // Uncheck selected radio buttons if the custom amount was chosen
        function onCustomAmountFocus() {
                for (var i = 0; i < donateForm.length; i++) {
                        if (donateForm[i].type == 'radio') {
                                donateForm[i].onclick = function() {
                                        customAmount.value = '';
                                }
                        }
                        if (donateForm[i].type == 'radio' && donateForm[i].checked) {
                                checkedInd = i;
                                donateForm[i].checked = false;
                        }
                }
        }

        function onCustomAmountBlur() {
                var value = customAmount.value;
                if (value == '') {
                    // The user haven't entered other amount
                        donateForm[checkedInd].checked = true;
                }
        }

        function donateLater(){
                donationAddress.style.display = "block";
                donateFormContainer.style.display = "none";
        }

})();
Tip The code above contains an example of an inefficient code that in a loop assigns a click event handler to each radio button should the user click any radio button after visiting the Other Amount field. This was a Jerry’s understanding of how to reset the value of the customAmount variable. Jerry was not familiar with the capture phase of the events that can intercept the click event on the radio buttons container’s level and simply reset the value of customAmount regardless of which specific radio button is clicked.

Let’s improve this code a little bit. The idea is to intercept the click event during the capture phase (see the DOM Events section in Chapter 2) and if the Event.target is any radio button, perform customAmount.value = '';

var donateFormContainer = document.getElementById('donate-form-container');

// Intercept any click on the donate form in a capturing phase
donateFormContainer.addEventListener("click", resetCustomAmount, true);
function resetCustomAmount(event){

    // reset the customAmount
        if (event.target.type=="radio"){
                customAmount.value = '';
        }
}

The code of the onCustomAmountFocus() doesn’t need to assign function handlers to the radio buttons any longer:

function onCustomAmountFocus() {
        for (var i = 0; i < donateForm.length; i++) {
                if (donateForm[i].type == 'radio' && donateForm[i].checked) {
                        checkedInd = i;
                        donateForm[i].checked = false;
                }
        }
}

Adding Video

In this section we’ll add a video player to our Save Sick Child application. The goal is to play a short animation encouraging kids to fight the disease. We’ve hired a professional animation artist Yuri who has started working on the animation. Meanwhile let’s take care of embedding the video player showing any sample video file.

Adding the HTML5 Video Element

Let’s run the Aptana’s project called project-05-html5-video to see it working, and after that we’ll review the code. The new version of the Sick Save Child should look as in <<FIG3-12>. The users will see an embedded video player on the right that can play the video located in the assets/media folder of the Aptana’s project project-05-html5-video.

images/fig_03_12.png
Figure 35. The video player is embeded

Let’s see how our index.html has changed since its previous version. The bottom part of the main section includes the <video> tag. In the past, the videos in Web pages were played predominantly by the browser’s Flash Player plugin (even older popular plugins included RealPlayer, MediaPlayer, and QuickTime). For example, you could have used the HTML tag `<embed src="myvideo.swf" height="300" width="300">`and if the user’s browser supports Flash Player, that’s all you needed for basic video play. While there were plenty of open source video players, creation of the enterprise-grade video player for Flash videos became an important skill for some software developers. For example, HBO, an American cable network offers an advanced multi-featured video player embedded into www.hbogo.com for their subscribers.

In today’s world most of the modern mobile Web browsers don’t support Flash Player, and the video content providers prefer broadcasting videos in formats that are supported by all the browsers and can be embedded into Web page using the standard HTML5 element <video> (see its current working draft is published at http://www.w3.org/TR/html5/the-video-element.html).

The following code fragment illustrates how we’ve embedded the video into the bottom portion of our Web page (index.html). It includes two <source> elements, which allows to provide alternative media resources. If the Web browser supports playing video specified in the first <source> element, it’ll ignore the other versions of the media. For example, the code below offers two versions of the video file: intro.mp4 (in H.264/MPEG-4 format natively supported by Safari and Internet Explorer) and intro.webm (WebM format for Firefox, Chrome, and Opera).

<section id="main-bottom-section">
 <div id="video-container">
        <video controls poster="assets/media/intro.jpg"
               width="390px" height="240" preload="metadata">

                <source src="assets/media/intro.mp4" type="video/mp4">
                <source src="assets/media/intro.webm" type="video/webm">
                <p>Sorry, your browser doesn't support video</p>
        </video>

                <h3>Video header goes here</h3>
                <h5><a href="javascript:void(0);">More videos</a></h5>
 </div>
</section>

The boolean property controls asks the Web browser to display the video player with controls (the play/pause buttons, the full screen mode, et al.) If you wouldn’t use the property controls your JavaScript could would have to control the playback. The poster property of the <video> tag specifies the image to display as a placeholder for the video - this is the image you see on [FIG3-12]. In our case the preload valus is metadata, which means that we want the Web browser to preload just the first frame of the video its metadata. Should we used preload="auto", the video would start loading in the background as soon as the Web page was loaded unless the user’s browser doesn’t allow it (e.g. Safari on iOS) for saving the bandwidth.

All major Web browsers released in 2011 and later include their own embedded video players that support the <video> element. It’s great that your code doesn’t depend on the support of the Flash Player, but now video players look different depending on which browser the user has.

If neither .mp4 nor .webm files can be played, the content in the <p> tag displays the fallback message "Sorry, your browser doesn’t support video". If you need to support older Web browsers that don’t support HTML5 video, but support Flash Player, you can replace this <p> tag with the <object> and <embed> tags that embed another media file that Flash Player understands. Finally, if you believe that some users may have the browsers that support neither the <video> tag nor Flash Player, just add the links to the files listed in the <source> tags right after the closing </video> tag.

Embedding YouTube Videos

Another way to include videos in your Web application is by uploading them to YouTube first and then embedding if into your Web page. This provides a number of benefits:

  • The videos are hosted on Google’s servers and use their bandwidth.

  • The users can either watch the video as a part of your application’s Web page or, by clicking on the YouTube logo on the status bar of the video player you can continue watching the video from its original YouTube URL.

  • YouTube is streaming videos in the compressed form and the user can watch it as the bytes come in - it doesn’t require a video to be fully preloaded to the user’s device.

  • YouTube stores videos in several formats and automatically selects the best one based on the user’s Web browser (user agent).

  • The HTML code to embed a YouTube video is generated for you by pressing the Share and then Embed link by the video itself.

  • You can enrich your Web application by incorporating extensive video libraries by using the YouTube Data API. You can create fine tuned searches retrieving channels, playlists, videos, manage subscriptions, and authorize user requests.

  • Your users can save the YouTube videos on their local drive using free Web Browsers add-ons like DownloadHelper extension for Firefox or a RealDownloader.

Tip Youtube offers an Opt-In Trial of HTML5 video, which allows playing most of the videos using HTML 5 video (even those recorded for Flash Player).

Embedding a YouTube video into your HTML page is simple. Find the page with the video on YouTube and press the links Share and Embed located right under the video. Then select the size of your video player and HTTPS encryption if needed. When this is done, copy the generated iFrame section into your page.

Open the file index.html in the Aptana’s project-06-YouTube-video and you’ll see there a code that replaces the <video> tag of the previous project. It should look like this:

<section id="main-bottom-section">
 <div id="video-container">
  <div id="video-container">
        <iframe src="http://www.youtube.com/embed/VGZcerOhCuo?wmode=transparent&hd=1&vq=hd720"
                frameborder="0" width="390" height="240"></iframe>

        <h3>Video header goes here</h3>
        <h5><a href="javascript:void(0);">More videos</a></h5>
  </div>
 </div>
</section>

Note that the initial size of our video player is 390x240 pixels. The <iframe> wraps the URL of the video, which in this example ends with parameters hd=1 and vq=hd720. This is how you can force YouTube to load video in HD quality. Run the project-06-YouTube-video and if shows you a Web page that looks as in [FIG3-13].

images/fig_03_13.jpg
Figure 36. The YouTube player is embeded

Now let’s do yet another experiment. Enter the URL of our video directly in your Web browser, turn on the Firegug or Developer Tools. We did it in Firebug under Mac OS and selected the Net tab. Then HTML Response looked as in [FIG3-14]. YouTube recognized that this Web browser is capable of playing Flash content (FLASH_UPGRADE) and picked the QuickTime as a fallback (QUICKTIME_FALLBACK).

images/fig_03_14.jpg
Figure 37. HTTP Response object from YouTube

Our brief introduction to embedding videos in HTML is over. Let' keep adding new features to the Save Sick Child Web application. This time we’ll get familiar with the HTML5 Geolocation API.

Adding Geolocation Support

HTML5 includes the Geolocation API that allows programmatically figure out the latitude and longitude of the user’s device. Most of the people are accustomed to the non-Web GPS applications in cars or mobile devices that display maps and calculate distances based on the current coordinates of the user’s device or motor vehicle. But why do we need the Geolocation API in a desktop Web application?

The goal of this section is to demonstrate a very practical feature - finding registered sick children based on the user’s location. This way the users of the Save Sick Child can find the needy children in a particular geographical area. In this chapter you’ll just learn the basics of HTML5 GeoLocation API, but we’ll continue improving the location feature of the Save Sick Child in the next chapter.

Tip The World Wide Web Consortium has published proposed recommendation of the Geolocation API Specification.

Does your old desktop computer have a GPS hardware? Most likely it doesn’t. But its location can be calculated with varying degree of accuracy. If your desktop computer is connected to the network it has an IP address or your local Wi-Fi router may have an SSID given by the router vendor or your Internet provider so the location of your desktop computer is not a secret, unless you change the SSID of your Wi-Fi router. Highly populated areas have more Wi-Fi routers and cell towers so the accuracy increases. In any case, properly designed applications must to always ask the user’s permission to use the current location of her computer or other connected device.

Note The GPS signals are not always available. There are various location services that help identifying the position of your device. For example, Google, Apple, Microsoft, Skyhook and other companies use publicly broadcast Wi-Fi data from the wireless access point. Google Location Server uses Media Access Control (MAC) address to identify any device connected to the network.

Every Web Browser has a global object window, which includes the navigator object containing the information about the user’s browser. If the browser’s navigator object includes the property geolocation, geolocation services are available. While the Geolocation API allows you to get just a coordinate of your device and report the accuracy of this location, most applications use this information with some user-friendly UI, for example, the mapping software. In this section our goal is to demonstrate the following:

  1. How to use Geolocation API

  2. How to integrate the Geolocation API with Google Maps.

  3. How to detect id the Web browser supports geolocation services

Geolocation Basics

The new Aptana project is called project-07-basic-geolocation, where we simply assume that the Web browser supports the Geolocation. The Save Sick Child page will get a new container in the middle of the bottom main section, where we are planning to display the map of the current user location. But for now we’ll show there just the coordinates: latitude, longitude, and the accuracy. Initially, the map container is empty, but we’ll populate it from the JavaScript code as soon as the position of the computer is located.

<div id="map-container"></div>

The following code snippet from main.js makes a call to the navigator.geolocation object to get the current position of the user’s computer.

var mapContainer = document.getElementById('map-container');      // 1

function successGeoData(position) {
        var successMessage = "We found your position!";               // 2
        successMessage += '\n Latitude = ' + position.coords.latitude;
        successMessage += '\n Longitude = ' + position.coords.longitude;
        successMessage += '\n Accuracy = ' + position.coords.accuracy +
                                                              ' meters';
        console.log(successMessage);

        var successMessageHTML = successMessage.replace(/\n/g, '<br />');
        var currentContent = mapContainer.innerHTML;
        mapContainer.innerHTML = currentContent + "<br />"
                                           + successMessageHTML;       // 3

}

function failGeoData(error) {                                       // 4
        console.log('error code = ' + error.code);

        switch(error.code) {
                case error.POSITION_UNAVALABLE:
                        errorMessage = "Can't get the location";
                        break;
                case error.PERMISSION_DENIED:
                        errorMessage = "The user doesn't want to share location";
                        break;
                case error.TIMEOUT:
                        errorMessage = "Timeout -  Finding location takes too long";
                        break;
                case error.UNKNOWN_ERROR:
                        errorMessage = "Unknown error: " + error.code;
                        break;
        }
        console.log(errorMessage);
        mapContainer.innerHTML = errorMessage;
}

if (navigator.geolocation) {
        var startMessage = 'Your browser supports geolocation API :)';
        console.log(startMessage);
        mapContainer.innerHTML = startMessage;
        console.log('Checking your position...');
        mapContainer.innerHTML = startMessage + '<br />Checking your position...';

        navigator.geolocation.getCurrentPosition(successGeoData,
           failGeoData,                                            // 5
           {maximumAge : 60000,
                enableHighAccuracy : true,                             // 6
                timeout : 5000
           }
        );

} else {
        mapContainer.innerHTML ='Your browser does not support geolocation';
}
1 Get a reference to the DOM element map-container to be used for showing the results.
2 The function handler to be called in case of the successful discovery of the computer’s coordinates. If this function will be called it’ll get a position object as an argument.
3 Display the retrieved data on the Web page (see [FIG3-15]).
4 This is the error handler callback.
5 Invoke the method getCurrentPosition() passing it two callback function as arguments (for success and failure) and an object with optional parameters for this invocation.
6 Optional parameters: accept the cached value if not older than 60 seconds, retrieve the best possible results and don’t wait for results for more that 5 seconds. You may not always want the best possible results to lower the response time and the power consumption.

If you run the project-07-basic-geolocation, the Browser will ask you a question similar to "Would you like to share your location with 127.0.01?" Allow this sharing and you’ll see a Web page, which will include the information about your computer’s location similar to [FIG3-15].

Tip If you don’t see the question asking permission to share location, check the privacy settings of your Web browser - most likely you’ve allowed using your location some time in the past.
images/fig_03_15.jpg
Figure 38. The latitude and longitude are displayed
Tip If you want to monitor the position as it changes (the device is moving) use geolocation.watchPosition(), which implements internal timer and checks the position. To stop monitoring position use geolocation.clearWatch().

Integrating with Google Maps

Knowing the device coordinates is very important, but let’s make the location information more presentable by feeding the device coordinates to Google Maps API. In this version of Save Sick Child we’ll replace the gray rectangle from <<>FIG3-15> with the Google maps container. We want the user to see a familiar map fragment with a pin pointing at the location of her Web browser. To follow our "Show and Tell" style let’s see it working first. Run Aptana’s project-08-geolocation-maps and you’ll see a map with your current location as shown on [FIG3-16].

images/fig_03_16.jpg
Figure 39. Showing your current location

Now comes the "Tell" part. First of all, take a look at the bottom of the index.html file. It loads Google’s JavaScript library with their Map API (sensor=false means that we are not using a sensor like GPS locator):

<script src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>

In the past Google required developed to obtain an API key and include it in the above URL. Although some Google’s tutorials still mentions the API key, it’s not a must.

Note An alternative way of adding the <script> section to HTML page is by creating a script element. This gives you a flexibility of postponing the decision of which JavaScript to load. For example,
var myScript=document.createElement("script");
myScript.src="http://......somelibrary.js";
document.body.appendChile(myScript);

Our main.js will invoke the function for Google’s library as needed. The code that find the location of your device is almost the same as in the section Geolocation Basics. We’ve replaced the call to with geolocation.watchPosition() so this program can modify the position if your computer, tablet, or a mobile phone is moving. We store the returned value of the watchPosition() in the variable watcherID in case if you decide to stop watching the position of the device by calling clearWatch(watcherID). Also, we lowered the value of the maximumAge option so the program will update the UI more frequently, which is important if you are running this program while in motion.

(function() {

 var locationUI = document.getElementById('location-ui');
 var locationMap = document.getElementById('location-map');
 var watcherID;

 function successGeoData(position) {
   var successMessage = "We found your position!";
   var latitude = position.coords.latitude;

   var longitude = position.coords.longitude;
   successMessage += '\n Latitude = ' + latitude;
   successMessage += '\n Longitude = ' + longitude;
   successMessage += '\n Accuracy = ' + position.coords.accuracy
                                      + ' meters';
   console.log(successMessage);

   // Turn the geolocation position into a LatLng object.
   var locationCoordinates =
          new google.maps.LatLng(latitude, longitude);      // 1

   var mapOptions = {
        center : locationCoordinates,
        zoom : 12,
        mapTypeId : google.maps.MapTypeId.ROADMAP,         //  2
        mapTypeControlOptions : {
          style : google.maps.MapTypeControlStyle.DROPDOWN_MENU,
          position : google.maps.ControlPosition.TOP_RIGHT
        }
   };

   // Create the map
   var map = new google.maps.Map(locationMap, mapOptions);  // 3

   // set the marker and info window
   var contentString = '<div id="info-window-content">' +
        'We have located you using HTML5 Geolocation.</div>';

   var infowindow = new google.maps.InfoWindow({            // 4
        content : contentString,
        maxWidth : 160
   });

   var marker = new google.maps.Marker({                   //  5
        position : locationCoordinates,
        map : map,
        title : "Your current location"

   });

       google.maps.event.addListener(marker, 'click',      // 6
            function() {infowindow.open(map, marker);

       });

       // When the map is loaded show the message and
       // remove event handler after the first "idle" event
       google.maps.event.addListenerOnce(map, 'idle', function(){
        locationUI.innerHTML = "Your current location";
   })

 }

  // error handler
 function failGeoData(error) {
         clearWatch(watcherID);
        //the error processing code is omitted for brevity
 }

 if (navigator.geolocation) {
        var startMessage =
            'Browser supports geolocation API. Checking your location...';
        console.log(startMessage);

        var currentContent = locationUI.innerHTML;
        locationUI.innerHTML = currentContent +' '+startMessage;

        watcherID = navigator.geolocation.watchPosition(successGeoData,  // 7
            failGeoData, {
                maximumAge : 1000,
                enableHighAccuracy : true,
                timeout : 5000
        });

 } else {
        console.log('browser does not support geolocation :(');
 }
})();
1 Google API represents a point in geographical coordinates (latitude and longitude) as a LatLng object, which we instantiate here.
2 The object`google.maps.MapOptions` is an object that allows you to specify various parameters of the map to be created. In particular, the map type can be one of the following: HYBRID, ROADMAP, SATTELITE, TERRAIN. We’ve chosen the ROADMAP, which displays a normal street map.
3 The function constructor google.maps.Map takes two arguments: the HTML container where the map has to be rendered and the MapOption as parameters of the map.
4 Create an overlay box that will show the content describing the location (e.g. a restaurant name) on the map. You can do it programmatically by calling InfoWindow.open().
5 Place a marker on the specified position on the map.
6 Show the overlay box when the use clicks on the marker on the map.
7 Invoke the method watchPosition() to find the current position of the user’s computer.

This is a pretty basic example of the integrating GeoLocation with the mapping software. Google Maps API consists of dozens JavaScript objects and supports various events that allow you to build interactive and engaging Web pages that include maps. Refer to the Google Maps JavaScript API Reference for the complete list of available parameters (properties) of all objects used in project-08-geolocation-maps and more. In Chapter 4 you’ll see a more advanced example of using Google maps - we’ll read the JSON data stream containing coordinates of sick children so the donors can find them based on the specified postal code.

Browser Features Detection With Modernizr

Now we’ll learn how to use the detection features offered by a JavaScript library called Modernizr. This is a must have feature detection library that helps your application to figure out if the user’s browser supports certain HTML5/CSS3 features. Review the code of index.html from the Aptana’s project-08-1-modernizr-geolocation-maps. Note that the index.html includes two <script> sections - the Modernizr’s JavaScript gets loaded first, while our own main.js is loaded at the end of the <body> section.

<!DOCTYPE html>

<html class="no-js" lang="en">
        <head>
                <meta charset="utf-8">

                <title>Save Sick Child | Home Page</title>
                <link rel="stylesheet" href="assets/css/styles.css">

                <script src="js/libs/modernizr-2.5.3.min.js"></script>

        </head>
        <body>
       !--  Most of the HTML markup is omitted for brevity  --!

                <script src="js/main.js"></script>
        </body>
</html>

Modernizr is an open source JavaScript library that helps your script to figure out if the required HTML or CSS features are supported by the user’s browser. Instead of maintaining complex cross-browser feature matrix to see if, say border-radius is supported in the user’s version of Firefox, the Modernizer queries the <html> elements to see what’s supported and what’s not.

Note the following fragment on the top of index.html: <html class="no-js" lang="en">. For Modernizr to work, your HTML root element has to include the class named "no-js". On page load, the Modernizr will replace the no-js class with its extended version that lists all detected features, and those that are not supported will get a prefix no-. Run index.html from project-08-1-modernizr-geolocation-maps in Firefox and you’ll see in Firebug that the values of the class property of the html element are different now, and you can see from [Fig3-17] that our version of Firefox doesn’t support touch events (no-touch), flexbox (no-flexbox), et al.

images/fig_03_17.png
Figure 40. Modernizr changed the HTML’s class property

For example, there is a new way to do page layouts using co called CSS Flexible Box Layout Module. This feature is not widely supported yet, and as you can see from [FIG3-17], our Web browser doesn’t support it at the time of this writing. If the CSS file of your application will implement two class selectors .flexbox and .no-flexbox then the browsers that support flexible boxes will use the former and the older browsers - the latter.

When Modernizr loads it creates a new JavaScript object window.Modernizr with lots of boolean properties indicating if a certain feature is or is not supported (see [FIG3-18]).

images/fig_03_18.png
Figure 41. window.Modernizr object

Hence your JavaScript code can test if certain features are supported or not.

What if the Modernizer detects that a certain feature is not supported yet by a user’s older browser? You can include polyfills in your code that replicate the required functionality. You can write such a polyfill on your own or pick one from the collection that is located at Modernizr’s Github repository.

The Development version of Modernizr weighs 42Kb and can detect lots of features. But you can make it smaller by configuring the detection of only selected features. Just visit Modernizr and press the red Production button that will allow to configure the build specifically for your application. For example, if you’re just interested to detect the HTML5 video support, the size of the generated Modernizr library will be reduced to under 2Kb.

Let’s review the relevant code from project-08-1-modernizr-geolocation-maps that illustrate the use of Modernizr. In particular, Modernizr allows you to load one or the other JavaScript code based on the result of some tests.

NOTE: Actually, the Modernizr loader internally utilizes a tiny (under 2Kb) resource loader library yepnope.js, which can load both JavaScript and CSS. This library is integrated in Modernizr, but we just wanted to give a proper recognition to yepnope.js, which can be used as an independent resource loader too.

(function() {

  Modernizr.load({

        test: Modernizr.geolocation,

        yep: ['js/get-native-geo-data.js','https://www.google.com/jsapi'],

        nope: ['js/get-geo-data-by-ip.js','https://www.google.com/jsapi'],

        complete : function () {
                google.load("maps", "3",
                            {other_params: "sensor=false", 'callback':init});
        }
  });
})();

The code above invokes the function load(), which can take different arguments, but our example uses as an argument a specially prepared object with five properties: test, yep, nope, complete. The load() function will test the value of Modernizr.geolocation and if it’s true, it’ll load the scripts listed in the yep property. Otherwise it’ll load the code listed in the nope array. The code in the get-native-geo-data.js gets the user’s location the same way as it was done earlier in the section Integrating with Google Maps.

Now let’s consider the "nope" case. The code of the get-geo-data-by-ip.js has to offer an alternative way of getting the location for the browsers that don’t support HTML5 Geolocation API. We found the GeoIP JavaScript API offered by MaxMind, Inc.. Their service returns country, region, city, latitude and longitude, which can serve as a good illustration of how a workaround of a non-supported feature can be implemented. The code in get-geo-data-by-ip.js is very simple for now.

function init(){

 var locationMap = document.getElementById('location-map');
 locationMap.innerHTML="Your browser does not support HTML5 geolocation API.";

 // The code to get the location by IP from http://j.maxmind.com/app/geoip.js
 // will go here. Then we'll pass the latitude and longitude values to
 // Google Map API for drawing the map.

}

Most likely your browser supports HTML5 geolocation API, and you’ll see the map created by the script get-native-geo-data.js. But if you want to test a non-supported geolocation (the nope branch) either try this code in the older browser or change the test condition to look like this: Modernizr.fakegeolocation,.

Google has several JavaScript APIs, for example, Maps, Search, Feeds, Earths et al. Any of these APIs can be loaded by Google AJAX Loader google.load(). This is more generic way of loading any APIs comparing to loading maps from http://maps.googleapis.com/maps/api in the previous section on integrating geolocation and maps. The process of loading of the Google code with Google AJAX Loader consists of two steps:

  1. Load Google’s common loader script from https://www.google.com/jsapi

  2. Load the concrete module API specifying its name, version and optional parameters. In our example we are loading the maps API of version 3 passing an object with two properties: sensor=false and the name of the callback function to invoke right after the mapping API completes loading: 'callback':init.

Tip If you want to test your Web page in the specific old version of a particular Web browser, you can find their distributions at oldapps.com. For example, you can find all the old version of Firefox for Mac OS and for Windows.

Search and Multi-Markers With Google Maps

We’ve prepared for you a couple of more examples just to showcase the features of Google Maps API. The working examples will be included in the code accompanying the book, and we’ll provide very brief explanations below.

The Aptana’s project-09-map-and-search is an example of address search using Google Maps API. [FIG3-19] shows a fragment of the Save Sick Child page after we’ve entered the address "26 Broadway ny ny" in the search field. You can do a search by city or a zip code too. This can be a useful feature if you’d want to allow the users search for sick children living in a particular geographical area so their donation would be directed to specific people.

images/fig_03_19.png
Figure 42. Searching by Address

Our implementation of the search is shown in the code fragment from main.js. It uses geocoding, which is a process of converting an address into geographic coordinates (latitude and longitude). If the address is found, the code places a marker on the map.

var geocoder = new google.maps.Geocoder();

function getMapByAddress() {
 var newaddress = document.getElementById('newaddress').value;

 geocoder.geocode(                                    //  1
  {'address' : newaddress,
  'country' : 'USA'
  },

  function(results, status) {                       //  2
   console.log('status = ' + status);

   if (status == google.maps.GeocoderStatus.OK) {

        var latitude = results[0].geometry.location.lat();          // 3
        var longitude = results[0].geometry.location.lng();

        var formattedAddress = results[0].formatted_address;
        console.log('latitude = ' + latitude +
                    ' longitude = ' +  longitude);
        console.log('formatted_address = ' + formattedAddress);

        var message = '<b>Address</b>: ' + formattedAddress;
        foundInfo.innerHTML = message;

        var locationCoordinates =
              new google.maps.LatLng(latitude, longitude);         // 4
        showMap(locationCoordinates, locationMap);

   } else if (status == google.maps.GeocoderStatus.ZERO_RESULTS) { // 5
        console.log('geocode was successful but returned no results. ' +
         'This may occur if the geocode was passed a non-existent ' +
         'address or a latlng in a remote location.');

   } else if (status == google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
        console.log('You are over our quota of requests.');

   } else if (status == google.maps.GeocoderStatus.REQUEST_DENIED) {
        console.log('Your request was denied, ' +
        'enerally because of lack of a sensor parameter.');

   } else if (status == google.maps.GeocoderStatus.INVALID_REQUEST) {
        console.log('Invalid request. ' +
             'The query (address or latlng) is missing.');
  }
 });
}
1 Initiate request to the Gecoder object providing the GeocodeRequest object with the address and a function to process the results. Since the request to the Google server is asynchronous, the function is a callback.
2 When the callback will be invoked, it’ll get an array with results.
3 Get the latitude and longitude from the result.
4 Prepare the LatLng object and give it to the mapping API for rendering.
5 Process errors.

The Geocoding API is simple and free to use until your application reaches a certain number of requests. Refer to Google Geocoding API documentation for more details.

Jerry has yet another cool idea: show multiple markers on the map reflecting several donation campaigns and charity events that are going on at various locations. If we display this information on the Save Sick Child page more people may participate with their donations or other ways. We’ve just learned how to do an address search on the map, and if the application has an access to the data about charity events, we can display them as the markers on the map. Run the project-10-maps-multi-markers and you’ll see a map with multiple markers as in [FIG3-20]

images/fig_03_20.png
Figure 43. Multiple markers on the map

The JavaScript fragment below displays the map with multiple markers. In this example the data is hard-coded in the array charityEvents, but in the next chapter we’ll modify this example and will get the data from a file in a JSON form. The for-loop creates a marker for each of the event listed in the array charityEvents. Each element of this array is also an array containing the name of the city and state, the latitude and longitude, and the title of the charity event. You can have any other attributes of the charity events stored in such an array and display them when the user clicks on a particular marker in an overlay by calling InfoWindow.open().

(function() {

  var locationUI = document.getElementById('location-ui');
  var locationMap = document.getElementById('location-map');

  var charityEvents = [['Chicago, Il', 41.87, -87.62, 'Giving Hand'],
    ['New York, NY', 40.71, -74.00, 'Lawyers for Children'],
    ['Dallas, TX', 32.80, -96.76, 'Mothers of Asthmatics '],
    ['Miami, FL', 25.78, -80.22, 'Friends of Blind Kids'],
    ['Miami, FL', 25.78, -80.22, 'A Place Called Home'],
    ['Fargo, ND', 46.87, -96.78, 'Marathon for Survivors']
  ];

  var mapOptions = {
                center : new google.maps.LatLng(46.87, -96.78),
                zoom : 3,
                mapTypeId : google.maps.MapTypeId.ROADMAP,
                mapTypeControlOptions : {
                        style : google.maps.MapTypeControlStyle.DROPDOWN_MENU,
                        position : google.maps.ControlPosition.TOP_RIGHT
                }
        };

  var map = new google.maps.Map(locationMap, mapOptions);

  var infowindow = new google.maps.InfoWindow();

  var marker, i;

  for ( i = 0; i < charityEvents.length; i++) {
        marker = new google.maps.Marker({
                position : new google.maps.LatLng(charityEvents[i][1],
                                                  charityEvents[i][2]),
                map : map
        });

        google.maps.event.addListener(marker, 'click', (function(marker, i) {
                return function() {
                 var content = charityEvents[i][0] + '<br/>' + charityEvents[i][3];
                 infowindow.setContent(content);
                 infowindow.open(map, marker);
                }
        })(marker, i));

        google.maps.event.addListenerOnce(map, 'idle', function(){
                locationUI.innerHTML = "Donation campaigns and charity events.";
        })
  }

})();

Summary

This chapter has described the process of mocking the future Web site on by our Web Designer Jerry, who went a lot further than creating a number of images with short descriptions. Jerry created a working prototype of the Save Sick Child page. The next phase of improving this prototype is to remove the hard-coded data from the code and place them into external files. The next chapter will cover the JSON data format and how to fill our single-page application with the data using a set of techniques called AJAX.

Using AJAX and JSON

This chapter is about bringing the external data to HTML Web pages. In the previous chapters we’ve been using only hard-coded data - our goal was to see how to layout the Web page and how to change the layout in case some events have happened, e.g. the user clicked on the menu button. Now we’ll make sure that our single-page application Save Sick Child can request the data from the external sources and send them the data too. This comes down to two questions:

  1. How an HTML Web page can exchange the data with external data sources?

  2. What format to use for presenting the application data?

While there could be different answers to these questions, we’ll be using AJAX techniques as an answer to the first question and JSON data format as an answer to the second one. We’ll start this chapter with explaining why AJAX and JSON are appropriate choice for the Save Sick Child Web application and many others.

Why AJAX

If a user points her Web browser to one URL and then changes it to another, the new request will be sent to the new URL, and the new page will arrive and will be rendered by the browser. The URL may have been changed not because the user decided to go to visit a different Web site, but simply because the user selected a menu item that resulted in bringing a new Web page from the same domain. This was pretty much the only way Web sites were designed in the 90th.

Back in 1999, Microsoft decided to create a Web version of Outlook - their popular eMail application. Their goal was to be able to modify the Input folder as the new emails arrive, but without refreshing the entire content of the Web page. They created an ActiveX control called XMLHTTP that lived inside Internet Explorer 5 and could make requests to the remote servers receiving data without the need to refresh the entire Web page. Such a Web Outlook client would would make periodic requests to the mail server, and if the new mail arrived the application would insert the new row on the top of the Inbox by direct change of the DOM object from JavaScript.

In early 2000th, other Web browsers adopted this model and implemented their own versions of XMLHTTPRequest. Its Working Draft 6 is published by W3C. Google created their famous email client GMail and Map Web applications. In 2005 Jesse James Garrett wrote an article titled "AJAX: A New Approach to Web Applications". The Web developer community liked the term AJAX, which stand for Asynchronous JavaScript and XML, and this gave a birth to the new breed of Web applications that could update the content of just the portion of a Web page without re-retrieving the entire page. Interestingly enough, the last letter in the AJAX acronym stands for XML, while realistically presenting the data in the XML form is not required, and is seldom used as a data format in the client-server exchanges. JSON is used a lot more often to represent the data, but apparently AJAJ didn’t sound as good as AJAX.

Visit the Google Finance or Yahoo! Finance Web pages when the stock market is open, and you’ll see how the price quotes or other financial indicators are changing while the most of the content remains the same. This gives an illusion of the server pushing the data to your Web client. But most likely, it not a data push but rather periodic polling of the server’s data using AJAX. In the modern Web applications we expect to see more of the real server side data push using HTML5 WebSockets API, which is described in details in Chapter 9 of this book.

Why JSON

JSON stands for JavaScript Object Notation. It’s a more compact than XML way to represent the data. Besides, all modern Web Browsers understand and can parse JSON data. After learning the JavaScript object literals in Chapter 2, you’ll see that the presenting the data in JSON notation is almost the same as writing JavaScript object literals.

[FIG4-1] depicts a high level view of a typical Web application. All of the code samples from Chapter 2 and Chapter 3 were where written in HTML, JavaScript and CSS. in this chapter will add to the mix the XMLHttpRequest object that will send and receive the JSON content wrapped into HTTPRequest and HTTPResponse objects.

images/fig_04_01.png
Figure 44. Anatomy of a Web application

Back in the 90th, if a Web application would need some JavaScript code or data from the server, Web developers would wrap it into an HTML <iFrame> element and send it to the client, which would use the the eval() function to execute it. Today, there is no need to do this if you just want to send the data - format it as a JSON object and use the JSON parser.

When a Web page is loaded the user doesn’t know (and doesn’t have to know) that the page content was brought from several servers that can be located thousands miles apart. More often than not, when the user enters the URL requesting an HTML document, the server side code can engage several servers to bring all the data requested by the user. Some of the data are retrieved by making calls to one or more Web Services. The legacy Web services were build using SOAP + XML, but majority of today’s Web services are build using lighter RESTful architecture, and JSON has become a de facto standard data exchange format of the REST Web services.

How AJAX Works

Imagine a single-page application that needs some data to refreshed in real time. For example, our Save Sick Child application includes an online auction where people can bid and purchase some goods as a part of a charity event. If John from New York placed a bid on certain auction item, and some time later Mary from Chicago placed the higher bid on the same item, we want to make sure that John knows about it immediately, in real time. This means that the server-side software that received Mary’s bid has to push this data to all users who expressed their interest in the same item.

But the server has to send and the browser has to modify only the new price while the rest of the content of the Web page should remain the same. You can implement behavior using AJAX. But first, the bad news: you can’t implement the real-time server side push with AJAX. You can only emulate this behavior by using polling techniques, when the XMLHttpRequest object sits inside your JavaScript code and periodically sends HTTP requests to the server asking if there were any changes in bids since the last request.

If, for instance, the last request was made at 10:20:00AM, the new bid was placed at 10:20:02AM, and the application makes a new request (and updates the browser’s window) at 10:20:25AM, this means that the user will be notified about the price change with a three second delay. AJAX is still request-response based way of getting the server’s data, and strictly speaking, doesn’t offer a real real-time updates. Some people use the term near real time notifications.

Another bad news is that AJAX uses HTTP protocol for the data communication, which means that a substantial overhead in the form of HTTPResponse header will be added to the new price, and it can be as large as several hundred bytes. This is still better than sending the entire page to the Web browser, but HTTP adds a hefty overhead.

Note We’ll implement such an auction in Chapter 9 using a lot more efficient protocol called WebSockets, which supports a real-time data push and adds only several extra bytes to the data load.

Retrieving Data From the Server

Let’s try to implement AJAX techniques by implementing a data retrieval. The process of making an AJAX request is well defined and consists of the following steps:

  • Create an instance of XMLHttpRequest object.

  • Initialize the request to your data source by invoking the method open().

  • Assign the a handler to the onreadystatechange attribute to process server’s response.

  • Make a request to the data source by calling send().

  • In your handler function process the response when it arrives from the server.

  • Modify the DOM elements based on the received data, if need be.

In most of the books on AJAX you’ll see browser-specific ways of instantiating the XMLHttpRequest object (a.k.a. XHR). Most likely you’ll be developing your application using some JavaScript framework and all browser specifics in instantiating of the XMLHttpRequest will be hidden from you. Chapters 6 and 7 include such examples, but let’s stick to the standard JavaScript way implemented by all modern browsers:

var xhr = new XMLHttpRequest();

The next step is to initialize a request by invoking the method open(). You need to provide the HTTP method (GET, POST et al.), the URL of the data source. Optionally, you can provide three more arguments: a Boolean variable indicating if you want this request to be processed asynchronously (which is the default), and the user id and password if the authentication is required. Keep in mind, that the following method does not request the data yet.

xhr.open('GET', dataUrl);

Tip Always use HTTPS ptotocol if you need to send the user id and password. Using secure HTTP should be your preferred protocol in general (read more in Chapter 10).

XHR has an attribute readyState, and as soon as it changes the callback function assigned to the onreadystatechange will be invoked. This callback should contain your application specific code to analyze the response and process it accordingly. Assigning such a callback is pretty simple:

xhr.onreadystatechange = function(){...}

Inside such a callback function you’ll be analyzing the value of the XHR’s attribute readyState, which can have one of the following values:

Table 1. States of the Request
Value State Description

0

UNSENT

the XHR has been constructed

1

OPENED

open() was successfully invoked

2

HEADERS_RECEIVED

All HTTP headers has been received

3

LOADING

The response body is being received

4

DONE

the data transfer has been completed

Finally, send the AJAX request for data. The method send() can be called with or without parameters depending on if you need to send the data to the server or not. In its simplest fore the method send() can be invoked as follows:

` xhr.send();`

The complete cycle of the readyState transitions is depicted in [FIG4-2]

images/fig_04_02.png
Figure 45. Transitions of the readyState attribute

Let’s spend a bit more time discussing the completion of the this cycle when server’s response is received and the XHR’s readyState is equal to 4. This means that we’ve got something back, which can be either the data we’ve expected or the error message. We need to handle both scenarios in the function assigned to the onreadystatechange attribute. This is a common way to do it in JavaScript without using frameworks:

xhr.onreadystatechange = function(){

 if (xhr.readyState == 4) {

   if((xhr.status >=200 && xhr.status <300) || xhr.status===304) {

       // We got the data. Get the value from one of the response attributes
       // e.g. xhr.responseText and process the data accordingly.

   } else {
      // We got an error. Process the error code and
      // display the content of the statusText attribute.
   }

  }
};

First the code should check the HTTP status code received from server. W3C splits the HTTP codes into groups. The codes numbered as 1xx are informational, 2xx are successful codes, 3xx are about redirections, 4xx represent bad requests (like infamous 404 for Not Found), and 5xx for server errors. That’s why the above code fragment checks for all 2xx codes and 304 - the data was not modified and taken from cache.

To see the first example where we are using AJAX in our Save Sick Child application run the Aptana’s project-04-1-donation-ajax-html, where we’ve removed the countries and states from HTML and saved them in two separate files: data/us-states.html and data/countries.html. The user’s of Save Sick Child page won’t find any visual differences, but the Countries and States dropdowns are now populated be the data located in these files. Later in this chapter in the section on JSON we’ll replace this HTML file with its JSON version. These are the first three lines (out of 241) from the file countries.html:

<option value="United States">United States</option>
<option value="United Kingdom">United Kingdom</option>
<option value="Afghanistan">Afghanistan</option>

The JavaScript code that reads countries and states from file and populates the dropdowns comes next. The content of these files is assigned to the innerHTML attribute of the given HTML <select> element.

function loadData(dataUrl, target) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', dataUrl, true);
  xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
           if((xhr.status >=200 && xhr.status <300) ||
                                 xhr.status===304){

                        target.innerHTML += xhr.responseText;
          } else {

                        console.log(xhr.statusText);
          }
        }
  }
  xhr.send();
}

// Load the countries and states using XHR
loadData('data/us-states.html', statesList);
loadData('data/countries.html', counriesList);
Note The above code has an issue, which may not be so obvious, but can irritate users. The problem is that it doesn’t handle errors. Yes, we print the error message on the developer’s console, but the end user will never see them. If for some reason the data about countries or states won’t arrive, the dropdowns will be empty, the donation form won’t be valid and the users will become angry that they can’t make a donation without knowing why. Proper error handling and reports are very important for any application so never ignore it. You should display a user-friendly error messages on the Web page. For example the above else statement can display the received message in the page footer

else { console.log(xhr.statusText);

        // Show the error message on the Web page
      footerContainer.innerHTML += '<p class="error">Error getting ' +
                    target.name + ": "+ xhr.statusText + ",code: "+
                     xhr.status + "</p>";
}

This code uses the CSS selector error that will show the error message on the red background. you can find it in the file styles.css in Aptana’s project-04-3-donation-error-ajax-html. It looks like this:

footer p.error {
        background:#d53630;
        text-align:left;
        padding: 0.9em;
        color: #fff;
}

The following code fragment shows how to add the received data to a certain area on the Web page. This code creates an HTML paragraph <p> with the text returned by the server and then adds this paragraph to the <div> with the ID main:

if (xhr.readyState == 4) {
  if((xhr.status >=200 && xhr.status <300) || xhr.status===304){
      var p = document.createElement("p");

      p.appendChild(document.createTextNode(myRequest.responseText));

      document.getElementById("main").appendChild(p);
  }
}

Sending Data to the Server

The next example to consider is when the Web client sends the data to the server using XMLHttpRequest object. The user of Save Sick Child fills out the Donate form and presses the button Donate.

AJAX: Good and Bad

AJAX techniques have their pros and cons. You saw how easy it was to create a Web page that didn’t have to refresh itself, but provided the users with the means of communicating with the server. This certainly improves the user experience. The fact that AJAX allows you to lower the amount of data that goes over the wire is important too. Another important advantage of AJAX that it works in a standard HTML/JavaScript environment and is supported by all Web browsers. The JavaScript frameworks hides all the differences in instantiating XMLHttpRequest and simplify making HTTP requests and processing responses. Since the entire page is not reloaded, you can create "fat clients" that keep certain data preloaded once and reused in your JavaScript in different use cases. With AJAX you can lazy load some content as needed rather than loading everything at once. Taken for granted auto-completion feature would not be possible in HTML/JavaScript application without the AJAX.

On the bad side, with AJAX the user loses the functionality of the browser’s Back button, which reloads the previous Web page while the user could expect to see the previous state of the same page. Since the AJAX brings most of the content dynamically, the search engines wouldn’t rank your Web pages as high as it would do if the content was statically embedded in the HTML. Increasing the amount of AJAX interactions means that your application will have to send more of the JavaScript code to the Web browser, which increases the complexity of programming and decreases the scalability of your application.

AJAX applications are subject to the same origin policy (the same protocol, port, and host) allowing XMLHttpRequest make HTTP requests only to the domains where the Web application was loaded from.

Tip W3C has published a working draft of Cross-Origin Resource Sharing (CORS) - a mechanism to enable client-side cross-origin requests.

Using JSON

In any client-server application one of the important decisions to be made is about the format of the data that go over the network. We are talking about the application-specific data. Someone has to decide how to represent the data about an Auction Item, Customer, Donation et al. The easiest way to represent text data is Comma Separated Format (CSV), but it’s not easily readable by humans, hard to validate, and recreation of JavaScript objects from CSV feed would require additional information about the headers of the data.

Sending the data in XML form addresses the readability and validation issues, but it’s very verbose. Every data element has to be surrounded by an opening and closing tag describing the data. Converting the XML data to/from JavaScript object requires special parsers, and you’d need to use one of the JavaScript libraries for cross-browser compatibility.

In today’s Web, JSON became the most popular data format. It’s not as verbose as XML, and JSON’s notation is almost the same as JavaScript object literals. It’s easily readable by humans, and every ECMAScript 5 compliant browser includes a native JSON object: window.JSON. Even though the JSON formatted data look like JavaScript object literals, JSON is language independent. Here’s an example of the data in the JSON format:

{
 "fname":"Alex",
 "lname":"Smith",
 "age":30,
 "address": {
     "street":"123 Main St.",
     "city": "New York"}
}

Anyone who knows JavaScript understands that this is an object that represents a person, which has a nested object that represents an address. Note the difference with JavaScript literals: the names of the properties are always strings, and every string must be taken into quotes. Representing the same object in XML would need a lot more characters (e.g. <fname>Alex</fname> etc).

There are some other important differences between JSON and XML. The structure of the XML document can be defined using DTD or XML Schema, which simplifies the data validation, but requires additional programming and schema maintenance. On the other hand, JSON data have data types, for example the age attribute in the above example is not only a Number, but will be further evaluated by the JavaScript engine and will be stored as an integer. JSON also supports arrays while XML doesn’t.

For parsing JSON in JavaScript you use the method JSON.parse(), which takes a string and returns JavaScript object, for example:

var customer=JSON.parse('{"fname":"Alex","lname":"Smith"}');

console.log(“Your name is ” + customer.fname + “ “ + customer.lname);

For a reverse operation - turning an object into JSON string - do JSON.stringify(custormer). The older browsers didn’t have the JSON object, and there is an alternative way of parsing JSON is with the help of the script json2.js, which creates the JSON property on the global object. The json2.js is freely available on Github. In Chapter 3 you’ve learned about feature detection with Modernizr, and you can automate the loading of this script if needed.

Modernizr.load({
    test: window.JSON,
    nope: 'json2.js',
    complete: function () {
        var customer = JSON.parse('{"fname":"Alex","lname":"Smith"}');
    }
});

Usually, JSON-related articles and blogs are quick to remind you about the evil nature of the JavaScript function eval() that can take an arbitrary JavaScript code and execute it. The JSON.parse() is pictured as a protection against the malicious JavaScript that can be injected into your application’s code and then executed by eval() by the Web browser. The main argument is that JSON.parse() will not be processing the incoming code unless it contains valid JSON data.

Protecting your application code from being infected by means of eval() can be done outside of your application code. Replacing HTTP with secure HTTPS protocol helps a lot in this regard. Some Web applications eliminate the possibility of cross-origin scripting by routing all requests to third-party data sources via proxying such requests through your trusted servers. But proxying all requests through your server may present scalability issues - imagine if thousands of concurrent users will be routed through your server - so do some serious load testing before making this architectural decision.

Running Aptana’s project project-04-2-donation-ajax-json reads the countries and states from the files countries.json and us_states.json respectively. The beginning of the file countries.json is shown below:

{
"countrieslist": [
        {
                "name": "Afghanistan",
                "code": "AF"
        }, {
                "name": "Åland Islands",
                "code": "AX"
        }, {
                "name": "Albania",
                "code": "AL"
        },
Tip There are several JSON tools useful for developers. To make sure that your JSON data is valid and properly formatted use using JSONLint. If you paste an ugly one-line JSON data JSLint will reformat it into a readable form. There is also an add-on JSONView, available both for Firefox and for Chrome browsers. With JSONView the JSON objects are displayed in a pretty formatted collapsible format. If there are errors in the JSON document they will be reported. At the time of this writing Chrome’s version of JSONView does a better job in reporting errors.

JSON supports arrays, and the next example shows you how the information about a customer can be presented in JSON format. A customer can have more than one phone, which are stored in an array.

<script >
   var customerJson = '{"fname":"Alex",
                        "lname":"Smith",
                        "phones":[
                            "212-555-1212",
                            "565-493-0909"
                        ]
                       }';

   var customer=JSON.parse(customerJson);

   console.log("Parsed customer data: fname=" + customer.fname +
                      " lname=" + customer.lname +
                      " home phone=" + customer.phones[0] +
                      " cell phone=" + customer.phones[1]);
</script>

The code above creates an instance of the JavaScript object referenced by the variable customer. In this example the phones array just holds two strings. But you can store object in JSON array the same way as you’d do it in JavaScript object literal - just don’t forget to put every property name in quotes.

var customerJson = '{"fname":"Alex",
                     "lname":"Smith",
                   "phones":[
                        {"type":"home", "number":"212-555-1212"},
                         {"type":"work","number":"565-493-0909"}]
                    }';

Loading Charity Events using AJAX and JSON

The last example in Chapter 3 was about displaying various charity events on the Google map using multiple markers. But the data about these events were hard-coded in HTML file. After getting familiar with AJAX and JSON it should not be too difficult to create a separate file with the information about charities in JSON format and load them using XMLHTTPRequest object.

The next version of Save Sick Child is a modified version of the application that displayed Google map with multiple markers from Chapter 3. But this time we’ll load the information about the charity events from the file campaigndata.json shown next.

{
  "campaigns": {
    "header": "Nationwide Charity Events",
    "timestamp":"12/15/2012",
    "items": [
      {
        "title": "Lawyers for Children",
        "description":"Lawyers offering free services for sick children",
        "location":"New York,NY"
      },
      {
        "title": "Mothers of Asthmatics",
        "description":"Mothers of Asthmatics - nationwide Asthma network",
        "location": "Dallas,TX"
      },
      {
        "title": "Friends of Blind Kids",
        "description":"Semi-annual charity events for blind kids",
        "location":"Miami,FL"
      },
      {
        "title": "A Place Called Home",
        "description":"Adoption of sick children",
        "location":"Miami,FL"
      },
      {
        "title": "Marathon for Survivors",
        "description":"Annual marathon for cancer survivors",
        "location":"Fargo, ND"
      }
    ]
  }
}

Run the Aptana’s project-11-maps-json-data and you’ll see the map with the markers for each of the events loaded from the file campaigndata.json (see [FIG4-03]). Click on the marker to see an overlay with the event details.

images/fig_04_03.png
Figure 46. Markers built from JSON data

Note that this JSON file contains the object campaigns, which includes the array of objects items representing charity events. XMLHttpRequest object loads the data and the JSON parses it assigning the campaigns object to the variable campaignsData that is used in showCampaignsInfo() with Google Maps API (we’ve omitted the mapping part for brevity).

function showCampaignsInfo(campaigns) {

        campaignsCount = campaigns.items.length;

        var message = "<h3>" + campaigns.header + "</h3>" +
                              "On " + campaigns.timestamp +
                        " we run " + campaignsCount + " campaigns.";

    locationUI.innerHTML = message + locationUI.innerHTML;
        resizeMapLink.style.visibility = "visible";

        createCampaignsMap(campaigns);
}

function loadData(dataUrl) {
 var xhr = new XMLHttpRequest();
 xhr.open('GET', dataUrl);

 xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
          if ((xhr.status >= 200 && xhr.status < 300) ||
                                    xhr.status === 304) {
                var jsonData = xhr.responseText;

                var campaignsData = JSON.parse(jsonData).campaigns;
                showCampaignsInfo(campaignsData);
         } else {
                console.log(xhr.statusText);

           tempContainer.innerHTML += '<p class="error">Error getting ' +
                 target.name + ": "+ xhr.statusText +
                 ",code: "+ xhr.status + "</p>";
         }
        }
 }
 xhr.send();
}

var dataUrl = 'data/campaignsdata.json';
loadData(dataUrl);
Tip Some older Web browsers may bring up a File Download popup window when the content type of the server’s response is set to "application/json". Try to use the MIME type "text/html" instead, if you ran into this issue.

Large-scale Web applications could be integrated with some content management systems (CMS), which can be supplying content such as charity events, sales promotions, et al. CMS servers can be introduced into the architecture of a Web application to separate the work on preparing the content from the application delivering it as shown in [FIG4-4] depicting a diagram of a with a Web application integrated with the CMS server.

images/fig_04_04.png
Figure 47. CMS in the picture

The content contributors and editors prepare the information on the charities and donation campaigns using a separate application, not the Save Sick Child page. The CMS server and the Web application server www.savesickchild.org may be located in the same or separate data centers. The server-side code of the Save Sick Child is making a call to a CMS server whenever the site visitor is requesting the information about charity events. If you get to pick a CMS for your future Web application make sure it offers data feed in JSON format.

Some time ago one of the authors of this book was helping Mercedes Benz USA in development of their consumer facing Web application where people could search, review and configure their next car. [FIG4-5] shows a snapshot taken from the mbusa.com. Three rectangular areas at the bottom were created by the Web designers to display today’s deals and promotions. The up-to-date content for these areas was retrieved from a CMS server when the user visited mbusa.com.

images/fig_04_05.png
Figure 48. Current Mercedes deals from CMS

JSON in Java

If a Web browser receives JSON stream from the server the application needs to turn it into JavaScript objects. If a Web client needs to send the JavaScriot objects to the server they can be converted into JSON string. Similar tasks have to be performed on the server side. Our Save Sick Child application uses Java application server. There is a number of third-party Java libraries that can consume and generate JSON content.

There are several Java libraries to convert Java objects into their JSON representation and back, for example Google’s Gson, Jackson, json-simple.

Google’s Gson is probably the simplest one for use. It provides methods toJson() and fromJson() to convert Java objects to JSON and back. Gson allows pre-existing un-modifiable objects to be converted to and from JSON and Supports Java Generics. Gson works well with complex objects with deep inheritance hierarchies.

Let’s say JavaScript sends to Java the following JSON string:

{"fname": "Alex", "lname":"Smith","skillLevel": 11}

The Java code can turn it into an instance of the Customer object by calling the method Gson.fromJson(). Similarly, Java code can create a JSON string from an object instance. Both of these operations are illustrated below.

public Customer createCustomerFromJson(String jsonString){

    Gson myGson = new Gson();
    Customer cust = myGson.fromJson(jsonString, Customer.class);
    return cust;
}

public String createJsonFromCustomer(Customer cust){

        Gson gson = new Gson();

        return gson.toJson(cust, Customer.class);
}

Of course, the declaration of the Java class Customer must exist in the in the classpath and don’t forget to include gson.jar to your Java project.

Tip JSON data format is often used in non-JavaScript applications. For example, a Java server can exchange the JSON-formatted data with a .Net server.
Note The upcoming Java EE 7 specification includes JSR 353, which defines a standardized way for parsing and generating JSON. JSR 353 defines the Java API from JSON Processing (JSON-P) that shouldn’t be confused with another acronym JSONP or JSON-P, which is JSON with Padding (we’ll discuss it at the end of this chapter).

Compressing JSON

JSON format is more compact than XML and is readable by the human beings. But when you are ready to deploy your application in production, you still want to compress the data so less bytes will travel over the wire to the user’s browser. The server-side libraries that generate JSON will make the data sent to the client compact by removing the tab and the new line characters.

If you want to turn the pretty-print JSON into a more compact one-line format just use such Web sites as JavaScript Compressor or JSON Formatter. For example, after running the 12Kb file countries.json through this compressor, its size was decreased to 9Kb. JSONLint can also compress JSON if you provide this URL: http://jsonlint.com?reformat=compress.

Similarly to most of the content that is being sent to browsers by the Web servers, the JSON data should be compressed. GZip and Deflate are the two main compression methods used in today’s Web. Both use the same compression algorithm deflate, but while with Deflate the compressed data are being streamed to the client, the GZip first compresses the entire file, calculates the size and adds some additional headers to the compressed data. So GZip may need some extra time and memory, but you are more protected from getting incomplete JSON, JavaScript or other content. Both Gzip and Deflate are easily configurable by major Web servers, but it’s hard to say which one is better for your application - set up some tests with each of them and decide which one works faster or take less system resources, but don’t compromise on reliability of the compressed content.

We prefer using GZip, which stands for GNU zip compression. On the server side you’d need to configure the gzip filters on your Web server. You need to refer to your Web server’s documentation to find out how to configure gzipping, which is done by the MIME type. For example, you can request to gzip everything except images (you might want to do this if you’re not sure if all browsers can properly uncompress certain MIME types).

For example, applying the GZip filter to the 9Kb countries.json will reduce its size to 3Kb, which means serious bandwidth savings especially in the Web applications with lots of concurrent users. This is even more important for the mobile Web clients, which may be operating in the areas with slower connections. The Web clients can set the HTTP request attribute Accept-Encoding: gzip inviting the server to return gzipped content, and the Web server may compress the response if it does support it or unzipped content otherwise. If the server supports gzip, the HTTP response will have the attribute Content-Encoding: gzip, and the browser will know to unzip the response data before use.

Gzip is being used for compressing all types of content: HTML, CSS, JavaScript and more. If your server sends JSON content to the client setting the content type to application/json don’t forget to include this MIME type in your server configuration for Gzip.

Web browsers support the gzipping too, and your application can set Content-Ecoding: gzip in HTTP request while sending the data from the Web client to the server. But Web clients usually don’t send massive amounts of data to the server so the benefits of the compression on the client side may not be as big.

Adding Charts to Save Sick Child

Let’s consider yet another use case for JSON in Save Sick Child. We want to display charts with statistics about the donations. By now, our application look not exactly as the original mockup from [FIG3-2], but it’s pretty close. There is an empty space in the left to the maps, and the charts showing donation statistics can fit right in. Now we need to decide how to draw the charts using nothing, but HTML5 elements. Note that we are not talking about displaying static images using the <img> element - the goal is to draw the images dynamically in the client’s code. You can accomplish this goal using HTML5 elements <canvas> or <svg>.

The <canvas> element provides a bitmap canvas, where your scripts which can draw graphs, game graphics, or other visual images on the fly without using any plugins like Flash Player or Silverlight. To put it simple, the <canvas> defines a rectangular area that consists of pixels, where your code can draw. Keep in mind that the DOM object can’t peek inside the canvas and access specific pixels. So if you are planning to create an area with dynamically changed graphics you might want to consider using <svg>.

The <svg> element supports Scalable Vector Graphics (SVG), which is the XML-based language for describing two-dimensional graphics. Your code has to provide commands to draw the lines, text, images et al.

Let’s review some code fragments from the Aptana’s project-12-canvas-pie-chart-json. The HTML section defines <canvas> of 260x240 pixels. If the user’s browser doesn’t support <canvas>, the user won’t see the chart, but will see the text "Your browser does not support HTML5 Canvas" instead. You need to give an ID to your canvas element so your JavaScript code can access it.

<div id="charts-container">
    <canvas id="canvas" width="260" height="240">
        Your browser does not support HTML5 Canvas
    </canvas>
    <h3>Donation Stats</h3>
    <p> Lorem ipsum dolor sit amet, consectetur</p>
</div>

Run the project-12-canvas-pie-chart-json, and you’ll see the chart with donation statistics by city as in [FIG4-6]. We haven’t style our <canvas> element, but we could’ve added a background color, the border and other bells and whistles if required.

images/fig_04_06.png
Figure 49. Adding a chart

The data to be used for drawing a pie chart in our canvas are stored in the file data/chartdata.json, but in a real-world the server side code can generate it based on the up-to-the-second donation data and send it to the client. For example, you could do it as was explained in the section Json in Java above. This is the content of our file chartdata.json:

{
  "ChartData": {
    "items": [
      {
        "donors": 48,
        "location":"Chicago, IL"
      },
      {
        "donors": 60,
        "location": "New York, NY"
      },
      {
        "donors": 90,
        "location":"Dallas, TX"
      },
      {
        "donors": 22,
        "location":"Miami, FL"
      },
      {
        "donors": 14,
        "location":"Fargo, ND"
      },
      {
        "donors": 44,
        "location":"Long Beach, NY"
      },
      {
        "donors": 24,
        "location":"Lynbrook, NY"
      }
    ]
  }
}

Loading of the the charddata.json is done using AJAX techniques as explained earlier. Although in our example we’re loading the chart immediately when the Save Sick Chile loads, the following code could be invoked only when the user requests to see the charts by clicking on some menu item on the page.

function loadData(dataUrl, canvas) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', dataUrl, true);

  xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if ((xhr.status >= 200 && xhr.status < 300) ||
                                      xhr.status === 304) {
                        var jsonData = xhr.responseText;

                        var chartData = JSON.parse(jsonData).ChartData;       // 1

                        var data = [];
                        var labels = [];

                        drawPieChart(canvas, chartData, 50, 50, 49);       // 2

                } else {
                        console.log(xhr.statusText);
                        tempContainer.innerHTML += '<p class="error">Error getting ' +
                               target.name + ": "+ xhr.statusText +
                               ",code: "+ xhr.status + "</p>";
                }
        }
  }
  xhr.send();
}

loadData('data/chartdata.json', document.getElementById("canvas"));
1 Parse JSON and create the ChartData Javascript object.
2 Pass the data to the drawPieChart() function that will draw the pie in the canvas element with the center coordinates x=50 and y=50 pixels. The top left corner of the canvas has coordinates (0,0). The radius of the pie will be 49 pixels. The code of the function that draws the pie on the canvas goes next.
function drawPieChart (canvas, chartData, centerX, centerY, pieRadius) {
        var ctx;  // The context of canvas
        var previousStop = 0;  // The end position of the slice
        var totalDonors = 0;

        var totalCities = chartData.items.length;

    // Count total donors
        for (var i = 0; i < totalCities; i++) {
                        totalDonors += chartData.items[i].donors;     // 1
        }

        ctx = canvas.getContext("2d");                        // 2
        ctx.clearRect(0, 0, canvas.width, canvas.heigh);

    var colorScheme = ["#2F69BF", "#A2BF2F", "#BF5A2F",   // 3
            "#BFA22F", "#772FBF", "#2F94BF", "#c3d4db"];

        for (var i = 0; i < totalCities; i++) {               // 4

                //draw the sector
                ctx.fillStyle = colorScheme[i];
                ctx.beginPath();
                ctx.moveTo(centerX, centerY);
                ctx.arc(centerX, centerY, pieRadius, previousStop, previousStop +
                        (Math.PI * 2 * (chartData.items[i].donors/totalDonors)),false);
                ctx.lineTo(centerX, centerY);
                ctx.fill();

                // label's bullet
                var labelY = 20 * i + 10;
                var labelX = pieRadius*2 + 20;

                ctx.rect(labelX, labelY, 10, 10);
                ctx.fillStyle = colorScheme[i];
                ctx.fill();

                // label's text
                ctx.font = "italic 12px sans-serif";
                ctx.fillStyle = "#222";
                var txt = chartData.items[i].location + " | " +
                                              chartData.items[i].donors;
                ctx.fillText (txt, labelX + 18, labelY + 8);

                previousStop += Math.PI * 2 * (chartData.items[i].donors/totalDonors);
        }
}
1 Count the total number of donors.
2 Get the 2D context of the <canvas> element. This is the most crucial element to know for drawing on a canvas.
3 The color scheme is just a set of colors to be used for painting each slice (sector) of the pie.
4 The for-loop paints one sector on each iteration. This code draws lines, arcs, rectangles, and adds text to the canvas. Describing the details of each method of the context object is out of scope of this book, but you can find the details of the context API in the W3C documentation available online.

What if we want to make this chart dynamic and reflect the changes in donations every 5 minutes? If you’re using <canvas>, you’ll need to redraw each and every pixel of our canvas with the pie. With SVG, each element of the drawing would be the DOM element so we could have redraw only those elements that have changed. If with canvas your script draws using pixels, the SVG drawings are done with vectors.

To implement the same donation statistics pie with the <svg> element, you’d need to replace the <canvas> element with the following markup:

<div id="charts-container">
        <svg id="svg-container" xmlns="http://www.w3.org/2000/svg">

        </svg>
        <h3>Donation Stats</h3>
        <p>
                Lorem ipsum dolor sit amet, consectetur
        </p>
</div>

Running the Aptana’s project-13-svg-pie-chart-json would show you pretty much the same pie as it uses the file chartdata.json with the same content, but the pie was produced differently. The code of the new version of the drawPieChart() is shown below. We won’t discuss all the details of the drawing with SVG, but will highlight the a couple of important lines of code that illustrate the difference between drawing on <canvas> vs. <svg>.

function drawPieChart(chartContaner, chartData, centerX, centerY,
                          pieRadius, chartLegendX, chartLegendY) {
        // the XML namespace for svg elements
        var namespace = "http://www.w3.org/2000/svg";
    var colorScheme = ["#2F69BF", "#A2BF2F", "#BF5A2F", "#BFA22F",
                      "#772FBF", "#2F94BF", "#c3d4db"];

        var totalCities = chartData.items.length;
        var totalDonors = 0;

     // Count total donors
        for (var i = 0; i < totalCities; i++) {
                totalDonors += chartData.items[i].donors;
        }

        // Draw pie sectors
        startAngle = 0;
        for (var i = 0; i < totalCities; i++) {
                // End of the sector = starting angle + sector size
                var endAngle = startAngle + chartData.items[i].donors / totalDonors * Math.PI * 2;
                var x1 = centerX + pieRadius * Math.sin(startAngle);
                var y1 = centerY - pieRadius * Math.cos(startAngle);
                var x2 = centerX + pieRadius * Math.sin(endAngle);
                var y2 = centerY - pieRadius * Math.cos(endAngle);

                // This is a flag for angles larger than than a half circle
                // It is required by the SVG arc drawing component
                var big = 0;
                if (endAngle - startAngle > Math.PI) {
                        big = 1;
                }

                //Create the <svg:path> element
                var path = document.createElementNS(namespace, "path");   // 1

        // Start at circle center
                var pathDetails = "M " + centerX + "," + centerY +       //  2
                // Draw line to (x1,y1)
                " L " + x1 + "," + y1 +
                // Draw an arc of radius
                " A " + pieRadius + "," + pieRadius +
                // Arc's details
                " 0 " + big + " 1 " +
                // Arc goes to to (x2,y2)
                x2 + "," + y2 +
                " Z";
                // Close the path at (centerX, centerY)

                // Attributes for the <svg:path> element
                path.setAttribute("d", pathDetails);
                // Sector fill color
                path.setAttribute("fill", colorScheme[i]);

                chartContaner.appendChild(path);                    // 3

                // The next sector begins where this one ends
                startAngle = endAngle;

                // label's bullet
                var labelBullet = document.createElementNS(namespace, "rect");
                // Bullet's position
                labelBullet.setAttribute("x", chartLegendX);
                labelBullet.setAttribute("y", chartLegendY + 20 * i);

    // Bullet's size
                labelBullet.setAttribute("width", 10);
                labelBullet.setAttribute("height", 10);
                labelBullet.setAttribute("fill", colorScheme[i]);

                chartContaner.appendChild(labelBullet);             // 3

                // Add the label text
                var labelText = document.createElementNS(namespace, "text");

    // label position = bullet's width(10px) + padding(8px)
                labelText.setAttribute("x", chartLegendX + 18);
                labelText.setAttribute("y", chartLegendY + 20 * i + 10);
                var txt = document.createTextNode(chartData.items[i].location +
                " | "+chartData.items[i].donors);

                labelText.appendChild(txt);
                chartContaner.appendChild(labelText);               //  3
        }

}
1 Create the <svg:path> HTML element, which is the most important SVG element for drawing basic shapes.. It includes a series of commands that produce the required drawing. For example, M 10 10 means movo to the coordinate 10,10 and L 20 30 means draw the line to the coordinate 20,30.
2 Fill the details of the <svg:path> element to draw the pie sector.

Run the Aptana’s project-13-svg-pie-chart-json to see the Save Sick Child page, then right-click on the pie chart and select Inspect Element (this is the name of the menu item in Firefox). [FIG4-7] shows the resulting content of our <svg> element. As you can see, it’s not pixel based but a set of XML-like commands that drew the content of the chart. If you’ll run the previous version of our application (project-12-canvas-pie-chart-json) and right-click on the chart, you will be able to save it as an image, but won’t see the internals of the <canvas> element.

1 Adding the internal elements of the chart container to the DOM - path, bullets and text. These elements can be modified if needed without redrawing the entire content of the container.
Tip in our code example we have written the path commands manually to process the data dynamically. But Web designers often use tools (Adobe Illustrator, Incscape et al.) to draw and then export images into an SVG format. In this case all paths will be encoded as <svg:path> automatically.
images/fig_04_07.png
Figure 50. The chart content in SVG

Since the SVG is XML-based, its very easy to generate the code shown in [FIG4-7] on the server, and lots of Web applications send ready to display SVG graphics to the users' Web browsers. But in our example we are generating the SVG output in the JavaScript from JSON received from the server, which provides a cleaner separation between the client and the server-side code. The final decision on what to send to the Web browser (ready to render SVG or raw JSON) has to be made after considering various factors such as available bandwidth, the size of data, the number of users, the existing load on the server resources.

Tip SVG supports animations and transformation effects, while canvas doesn’t.

What is JSONP

JSONP is a technique used in to relax the cross-origin restrictions in cases when a Web page was loaded from the domain abc.com and needs JSON-formatted data from another domain xyz.com. With JSONP, instead of sending plain JSON data, the server wraps them up into a JavaScript function and then sends it to the Web browser for execution as a callback. The Web page that was originated from abc.com may send the request http://xyz.com?callback=myDataHandler technically requesting the server xyz.com to invoke the JavaScript callback named myDataHandler. This URL is a regular HTTP GET request, which may have other parameters too so you can send some data to the server too.

The server will send to the browser the JavaScript function that may look as follow:

function myDataHandler({"fname": "Alex", "lname":"Smith","skillLevel": 11});

The Web browser will invoke the callback myDataHandler(), which must exist in the Web page. The Web browser will pass the received JSON object as an argument to this callback:

function myDataHandler(data){
  // process the content of the argument data - the JSON object
  // received from xyz.com
}

If all you need is just to retrieve the data from a different domain on page just add the following tag to your HTML page:

<script src="http://xyz.com?callback=myDataHandler">

But what if you need to dynamically make such requests periodically (e.g. get all twits with a hashtag #savisickchild by sending an HTTP GET using Twitter API at http://search.twitter.com/search.json?q=savesickchild&rpp=5&include_entities=true&with_twitter_user_id=true&result_type=mixed)? You may also need to make requests to a different server when the user selected a certain option on your Web page. You can achieve this by dynamically adding a <script> tag to the DOM object from your JavaScript code. Whenever the browser sees the new <script> element it executes it. Such script injection can be done like this:

var myScriptTag = document.createElement("script");
myScriptTag.src = "http://xyz.com?callback=myDataHandler";
document.getElementsByTagName("body").appendChild(myScriptTag);

Your JavaScript can build the URL for the myScriptTag.src dynamically and pass parameters to the server based on some user’s actions, for example:

myScriptTag.src = "http://xyz.com?city=Boston&callback=myDataHandler";

Of course, this technique presents a danger if there is a chance that the JavaScript code sent by xyz.com is intercepted and replaced by a malicious code. But it’s not more dangerous that receiving any JavaScript from non-trusted server. Besides, your handler function could always make sure that the received data is a valid object with expected properties, and only after that handle the data.

If you decide to use JSONP don’t forget about error handling. Most likely you’ll be using one of the JavaScript frameworks and they usually offer a standard mechanism for JSONP error handling, dealing with poorly formatted JSON responses, and recovery in cases of network failure. One of such libraries is called jQuery-JSONP.

Beer and JSONP

In this section you’ll see a small code example illustrating the data retrieval from publicly publicly available Open Beer DataBase, which exists to help software developers test their code that makes REST Web service calls and works with JSON and JSONP data. Our Save Sick Child page won’t display beer bottles, but we want to show that in addition to the retrieval of the donations and charts data from one domain we can get the data from a third-party domain openbeerdatabase.com.

First, enter the URL http://api.openbeerdatabase.com/v1/breweries.json in the address bar of your Web browser, and it’ll return the following JSON data (only 2 out of 7 breweries are shown for brevity):

{
   "page": 1,
   "pages": 1,
   "total": 7,
   "breweries": [
       {
           "id": 1,
           "name": "(512) Brewing Company",
           "url": "http://512brewing.com",
           "created_at": "2010-12-07T02:53:38Z",
           "updated_at": "2010-12-07T02:53:38Z"
       },
       {
           "id": 2,
           "name": "21st Amendment Brewing",
           "url": "http://21st-amendment.com",
           "created_at": "2010-12-07T02:53:38Z",
           "updated_at": "2010-12-07T02:53:38Z"
       }
   ]
}

Now let’s request the same data, but in a JSONP format by adding to the URL a parameter with a callback name myDataHandler. Entering in the browser http://api.openbeerdatabase.com/v1/breweries.json?callback=processBeer will return the following (it’s a short version):

processBeer({"page":1,"pages":1,"total":7,"breweries":[{"id":1,"name":"(512) Brewing Company","url":"http://512brewing.com","created_at":"2010-12-07T02:53:38Z","updated_at":"2010-12-07T02:53:38Z"},{"id":2,"name":"21st Amendment Brewing","url":"http://21st-amendment.com","created_at":"2010-12-07T02:53:38Z","updated_at":"2010-12-07T02:53:38Z"}]})

Since we haven’t declared the function processBeer() yet, it won’t be invoked. Let’s fix it now. The function will check first if the received data contains the information about the breweries. If it does, the name of the very first brewery will be printed on the JavaScript console. Otherwise the console output will read "Retrieved data has no breweries info".

var processBeer=function (data){

   // Uncomment the next line to emulate malicious data
   // data="function evilFunction(){alert(' Bad function');}";

     if (data.breweries == undefined){
      console.log("Retrieved data has no breweries info.");
     } else{
      console.log("In the processBeer callback. The first brewery is "
                  + data.breweries[0].name);
     }
  }

var myScriptTag = document.createElement("script");
  myScriptTag.src = "http://api.openbeerdatabase.com/v1/breweries.json?callback=processBeer";

var bd = document.getElementsByTagName('body')[0];
bd.appendChild(myScriptTag);

[FIG4-8] is a screen snapshot taken in the Firebug when it reached the breakpoint placed inside the processBeer callback on the console.log(in the processBeer callback"). You can see the content of the data argument - the beer has arrived.

images/fig_04_08.png
Figure 51. The beer has arrived
Tip As a training exercise, try to replace the data retrieval from the beer Web service with adding the data feed from Twitter based on certain hash tags. See if you can find the place in the Save Sick Child Web page to display (and periodically update) this Twitter stream.

Summary

In this chapter you’ve learned about using AJAX as a means of communications of your Web browser with the servers. AJAX also deserves a credit for making the JavaScript language popular again by showing a practical way of creating single-page Web applications. Over the years JSON became the standard way of exchanging the data on the Web. The current version of the Save Sick Child application cleanly separates the code from the data, and you know how to update the content of the Web page without the need to re-retrieve the entire page from the server. In the next chapter you’ll get familiar with the test-driven way of developing Web applications with JavaScript.

CHapter 5. Test-Driven Development with JavaScript

The idea: No more blog posts on Backbone.js or other JS frameworks without showing tests. The importance of JS testing needs to be stressed here.

http://twitter.com/bphogan/status/194856922208407552
— @bphogan

The chapter starts with a brief overview of available test frameworks. Then, it explains how to set up a new Save Sick Child project in the IDE using a selected test framework.

Upgrading HTTP to WebSockets

This chapter is about moving away from the HTTP protocol to more responsive HTML5 WebSockets. It starts with a brief overview of the existing legacy Web networking, and then you’ll learn why and how to use HTML5’s Server-Sent Events (SSE) and WebSockets.

The new version of our Save Sick Child application will include the online auction utilizing WebSockets, and you’ll see an example of using Server-Sent Events for broadcasting the up-to-the-minute donation information. The goal is to let you see the advantages of changing the way of client-server communications on the Web. You’ll clearly see the advantages of Websockets over a regular HTTP by monitoring the network traffic with such tools as Wireshark and Google Chrome Developer Tools.

All the server-side functionality supporting this chapter is written in Java, using Java API for WebSocket reference implementation, which will be the part of upcoming Java EE 7 specification. We are using the latest available build of the Glassfish Application Server. If you don’t know Java, just treat this server-side setup as a service that supports WebSockets. For Java developers interested in diving into the server-side, we’ll provide the source code and brief comments as a part of the code samples that come with this book.

We’ll show and compare the server-side data push done with Server-Sent Events and WebSockets. Also you’ll see a brief overview of popular existing frameworks that can streamline your WebSockets application development.

Near Real Time Applications With HTTP

The HTTP protocol is the lingua franca of today’s Web applications, where client-server communications are based on the request-response paradigm. On the low level, Web browsers establish a TCP/IP connection for each HTTP session. Currently there are 3 basic options that developers use for the browser-server communication: polling, long polling, and streaming. These options are hacks on the top of a half-duplex (a one way street) HTTP protocol to simulate real-time behavior. Lets discuss each of them.

Polling

With polling, your client code sends requests to the server after based on some pre-configured interval (e.g. using JavaScript setInterval() function). SOme of the server’s responses will be empty, if the requested data is not ready yet as illustrated in [FIG9-1]. For example, if you’re running an online auctions and sends the request to see the updated bids, you won’t receive any data back unless someone placed a new bid. Visualize a child seating on back seat of your car and asking every minute, "Have we arrived yet?" . And you’re politely replying, "Not just yet" - this is similar to an empty server response. There is no valuable payload for this kid, but she’s still receiving some "metadata". HTTP polling may result in receiving verbose HTTP response headers bearing no data load, let alone destructing the driver (think the server) from performing other responsibilities.

Polling

image

Long Polling

Long polling (see [FIG9-2] ) starts similarly to polling: the client sends the HTTP request to the server. But in this case instead of sending an empty response back, the server waits till the data for the client becomes available. If the requested information is not available within the specified time interval, the server sends an empty response to the client, closes, and re-establishes the connection.

We’ll give you one more analogy to compare polling and long polling. Imagine a party at the top floor of a building equipped with a smart elevator that goes up every minute and opens the door just in case if one of the guests wants to go down to smoke a cigarette. If no one enters the elevator, it goes to the ground level and in 60 seconds goes up again. This is the polling scenario. But if this elevator would go up, and waited till someone would actually decide to go down, then we could call it a long polling mode.

From the HTTP specification perspective this hack is legit: the long polling mode may seem as if we deal with the slow-responding server. That is why this technique also referred as Hanging GET. If you see an online auction that automatically modifies the prices as people bid on items it looks as if the server pushes the data to you. But the chances are, this functionality was implemented using long polling, which is not a real server-side data push, but its emulation.

Long Polling

image

HTTP Streaming

The client sends the request for data. As soon as the server gets the data ready, it starts streaming (adding more and more data to the response object) without closing the connections. The server pushes the data to the client pretending that the response never ends [FIG9-3]. For example, requesting a video from Youtube.com results in streaming data (frame after frame) without closing the HTTP connection.

HTTP Streaming

image

Polling and streaming can be used as a fall-back for legacy browsers that don’t support the HTML5 APIs Server-Sent Events and WebSockets.

Server-Sent Events

Before diving into the WebSockets protocol lets get familiar with the standardized way of implementing Server-Sent Events. W3C introduces API for Web browsers and the EventSource object. SSE allows browsers to subscribe to the server events arriving in the form of DOM events. The following code snippet shows the JavaScript code that can be used in a Web browser.

var source;
if( !! window.EventSource) {
    source = new EventSource('/donate_web/api/donations/events');  // 1
} else {
    console.log("sse not supported")
}

source.addEventListener('open', function(e) {                   // 2
    // Connection was opened.
}, false);

source.addEventListener('create', function(e) {                 // 3
    console.log(e.data);
}, false);

source.addEventListener('update', function(e) {                 // 4
    console.log(e.data);
}, false);

source.addEventListener('error', function(e) {
    if(e.readyState == EventSource.CLOSED) {
        // Connection was closed.
    }
}, false);
1 Create a new EventSource object. At this point the browser will send the GET request to the specified server-side endpoint to register itself on the server.
2 Add handlers for the open and error events.
3 Handle messages in create events.
4 Handle messages in update events.

Using SSE is a good technique for the use cases when the client doesn’t need to send the data to the server. In the above example the server sends two types of custom events create and update to notify subscribed clients about updated donation data so the active clients can monitor the fund-raising process. We can create as many custom events as needed by the application.

SSE is still HTTP-based, and it requires the server’s support of the combination of HTTP 1.1 keep-alive connections and the text/event-stream content type in HTTP response. The overhead is minimal - instead of hundreds of bytes in request and response headers, the server sends only the responses when the data has changed.

Introducing WebSockets

Reducing kilobytes of data to 2 bytes is more than "a little more byte efficient", and reducing latency from 150ms (TCP round trip to set up the connection plus a packet for the message) to 50ms (just the packet for the message) is far more than marginal. In fact, these two factors alone are enough to make WebSocket seriously interesting to Google.

Ian Hickson
— HTML spec editor at Google

WebSockets is a bi-directional full-duplex socket-based protocol. According to RFC 6455 - the Internet Engineering Task Force (IETF) standard document - the goal of WebSocket technology is to provide a mechanism for Web applications that need two-way communications with servers. This technology doesn’t rely on HTTP hacks or on opening multiple connections using XMLHttpRequest or <iframe> and long polling. The idea behind WebSockets is not overly complicated:

  • Establish a socket connection between the client and the server using HTTP for the initial handshake.

  • Switch the communication protocol from HTTP to a socket-based protocol.

  • Send messages in both directions simultaneously (a.k.a. full duplex mode).

  • Send messages independently. This is not a request-response model as both the server and the client can initiate the data transmission which enables the real server-side push.

  • Both the server and the client can initiate disconnects too.

You will get a better understanding of each of these statements after reading the section WebSocket API later in this chapter.

The WebSocket protocol defines two new URI schemes ws and wss for unencrypted and encrypted connections respectively. The ws (WebSocket) URI scheme is similar to HTTP URI scheme and identifies that a WebSocket connection will be established using TCP/IP protocol without encryption. The`wss` (WebSocket Secure) URI scheme identifies that the traffic over that connection will be protected via Transport Layer Security (TLS). The TLS connection provides such benefits over TCP connection as data confidentiality, integrity, and the endpoint authentication. Apart from the scheme name, WebSockets URI schemes use generic URI syntax.

WebSocket Interface

The W3C expert group uses Interface Description Language to describe what the WebSocket interface should look like. This is how it was defined:

[Constructor(DOMString url, optional (DOMString or DOMString[]) protocols)] //1
interface WebSocket : EventTarget {
  readonly attribute DOMString url;

  const unsigned short CONNECTING = 0;          //2
  const unsigned short OPEN = 1;
  const unsigned short CLOSING = 2;
  const unsigned short CLOSED = 3;
  readonly attribute unsigned short readyState;
  readonly attribute unsigned long bufferedAmount;

  // networking
  [TreatNonCallableAsNull] attribute Function? onopen;      //3
  [TreatNonCallableAsNull] attribute Function? onerror;
  [TreatNonCallableAsNull] attribute Function? onclose;
  readonly attribute DOMString extensions;
  readonly attribute DOMString protocol;                    //4
  void close([Clamp] optional unsigned short code, optional DOMString reason);

  // messaging
  [TreatNonCallableAsNull] attribute Function? onmessage;
           attribute DOMString binaryType;
  void send(DOMString data);            // 5
  void send(ArrayBufferView data);
  void send(Blob data);
};
1 The constructor requires an endpoint URI and optional sub-protocols names. A sub-protocol is an application-level protocol layered over the WebSocket Protocol. The client-side application can explicitly indicate which sub-protocols are acceptable for the conversation between the client and server. That string will be send to the server with the initial handshake as Sec-WebSocket-Protocol GET request header field. If the server supports one of the requested protocols it selects at most one of acceptable protocols and echoes that value in the same header parameter Sec-WebSocket-Protocol in the handshake’s response. Thereby the server indicates that it has selected that protocol. It could be a custom protocol or one of standard application level protocols. For example, it’s possible to transfer the SOAP or XMPP messages over the WebSocket connection. We’ll discuss the handshake in the [HANDSHAKE] section.
2 At any given time the WebSocket can be in one of four states.
3 These are the callback functions of WebSocket object that will be invoked by the browser once the appropriate network event is dispatched.
4 This property contains the name of the sub-protocol used for the conversation. After the successful handshake this property populated by the browser with value from servers response parameter Sec-WebSocket-Protocol as described in <1>.
5 The WebSocket object can send text or binary data to the server using on of the overloaded send() methods.
The Client-Side API

After introducing the WebSockets interface lets see the code example illustrating how the client’s JavaScript can use it.

var ws;
if(window.WebSocket) {    // 1
    console.log("WebSocket object is supported in your browser");   

    ws = new WebSocket("ws://www.websocket.org/echo"); // 2
    ws.onopen = function() { console.log("onopen"); 
    };  // 3 
     
    ws.onmessage = function(e) {
        console.log("echo from server : " + e.data);  // 4
    };

    ws.onclose = function() { // 5
        output("onclose"); 
    };
    ws.onerror = function() { output("onerror");  // 6
    };

} else {
    output("WebSocket object is not supported in your browser");
}
1 Not all Web browsers support WebSockets natively as of yet. Check if the WebSocket object is supported by the user’s browser.
2 Instantiate the new WebSocket object with passing an endpoint URI as constructor parameter.
3 Set the event handlers for open, message, close events.
4 The MessageEvent is dispatched when the data is received from the server. This message will be delivered to the function assigned to the WebSocket object’s onmessage property. The e.data property of the message event will contain the received message.
5 Handle closing connection (more details in [CLOSING] section).
6 Handle errors.
WebSockets Handshake

Any network communications that use WebSocket protocol start with an opening handshake. The handshake upgrades the connection from HTTP to the WebSockets protocol. It’s an upgrade to a message-based communications. We will discuss messages (a.k.a. frames) later in this chapter. Why upgrade from HTTP instead of starting with the TCP as a protocol in the first place? The reason is that the WebSocket operates on the same ports (80 and 443) as HTTP and HTTPS do. It’s an important advantage that the browser’s requests are routed through the same ports because arbitrary socket connections may not be allowed by the enterprise firewalls for security reasons. Also, many corporate networks only allow certain outgoing ports. And HTTP/HTTPS ports are usually included in so called white lists.

The protocol upgrade is initiated by the client request, which also transmits a special key with the upgrade request. The server processes this request and sends back a confirmation for the upgrade. This ensures that a WebSocket connection can be established only with an endpoint that support WebSockets. Here is what the handshake can look like in the client’s request:

    GET HTTP/1.1
    Upgrade: websocket
    Connection: Upgrade
    Host: echo.websocket.org
    Origin: http://www.websocket.org
    Sec-WebSocket-Key: i9ri+AfOgSsKwUlmLjIkGA==
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Protocol: chat

This client sends the GET request for the protocol upgrade. The Sec-WebSocket_Key is just a set of random bytes. The server takes these bytes and appends to this key a special Global Unique Identifier (GUID) string 258EAFA5-E914-47DA-95CA-C5AB0DC85B11, then it creates the Secure Hash Algorithm SHA1 hash from it performs the base64 encoding. The resulting string of bytes needs to be used by both the server and the client, and this string won’t be used by the network endpoints that do not understand the WebSockets protocol. Then this value would be copied in the Sec-WebSocket-Accept header field. The server computes the value and sends the response back confirming the protocol upgrade.

    HTTP/1.1 101 Web Socket Protocol Handshake
    Upgrade: WebSocket
    Connection: Upgrade
    Sec-WebSocket-Accept: Qz9Mp4/YtIjPccdpbvFEm17G8bs=
    Sec-WebSocket-Protocol: chat
    Access-Control-Allow-Origin: http://www.websocket.org

The WebSockets protocol uses the 400 Bad Request HTTP error code to signal the unsuccessful upgrade. The handshake can also include a sub-protocol request and the WebSocket version information but you can’t include arbitrary other headers. We can’t transmit the authorization information. There are two ways around this. You can either transmit the authorization information as the first request (e.g. unique clientId can be passed as part of the HTTP request header or HTML wrapper) or put it into the URL as a query parameter during the initial handshake. Consider the following example:

var clientId = "Mary1989";                                   // 1
ws = new WebSocket("ws://www.websocket.org/echo/"+clientID); // 2
1 The client the clientId value (can be obtained from some LDAP server).
2 The client connects to the WebSockets endpoint with an extra URI parameter which will be stored on server for future interactions.

Because WebSockets protocol creates a bi-directional (socket-to-socket) connection, the server has access to the conversation session associated with such a connection. This session can be associated with clientId and be stored on server.

Note A client can have as any WebSocket connections with the server as needed. But servers can refuse to accept connections from hosts/IP addresses with an excessive number of existing connections or disconnect resource-hogging connections in case of high data load.
The WebSocket Frame Anatomy

The WebSocket handshake is the first step to switching to the message framing protocol, which will be layered over TCP. In this section we’re going to explore how the WebSocket data transfer works. The WebSocket is not a stream based protocol like TCP - it’s message based. The difference is that with TCP a program sends stream of bytes, which has to have a specific indication that the data transfer ends. The WebSocket specification makes it easier because it puts a frame around every chunk of data, and the size of the frame is known. JavaScript can easily handle these frames on the client because each frame arrives packaged in the event object. But the server side has to work a little harder as it needs to wrap each piece of data into a frame before sending it to the client. A frame can look like this:

+-+-+-+-+-------+-+-------------+-------------------------------+
0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+
  • FIN (1 bit)

This bit indicates if this frame is the final in the message payload. If a message has under 127 bytes fits into a single frame and this bit will always be set.

  • RSV1, RSV2, RSV3 (1 bit each)

These bits are reserved for future protocol changes and improvements. They must contain zeros as they are not being used at this time.

  • opcode (4 bits)

+ .The frame type is defined using opcode. Here are the most used opcodes:

  • 0x00 This frame continues the payload.

  • 0x01 This frame includes UTF-8 text data.

  • 0x02 This frame includes the binary data.

  • 0x08 This frame terminates the connection.

  • 0x09 This frame is a Ping.

  • 0x10 This frame is a Pong.

    • mask (1 bit)

This indicates if the frame is masked.

Note The client must mask all the frames being sent to the server. The server must close the connection upon receiving a frame that is not masked. The server must not mask any frames that it sends to the client. The client must close a connection if it detects a masked frame. In that case of such error, client or server can send Close frame with 1002 status code - protocol error. All these actions are done automatically by Web browsers and Web server that support WebSockets.
  • payload_len (7 bits, 7+16 bits, or 7+64 bits)

The length of the payload. WebSocket frames come in the following length brackets: 0-125 indicate the length of the payload. 126 means that the following two bytes indicate the length. ** 127 means the next 8 bytes indicate the length.

  • masking-key (32 bits)

This key is used to XOR the payload with.

  • payload data

This indicates the actual data. The length of block is defined in the payload_len field.

The Heartbeats

Properly design distributed application has to have a way to ensure that each tier of the system is operational even if there is no active data exchange between the client and the server. This can be done by implementing so called heartbeats - a small messages that simply ask the other party, "Are you there?". For example, proxy servers and content-filtering hardware can terminate idle connections or the server could simply go down. If a client doesn’t send any requests, say for 20 seconds, but the server went down, the client will know about it only when it does the next send(). Heartbeats will keep the connection alive to ensure that it won’t look idling. In the WebSockets jargon heartbeats are implemented with ping and pong . The browser sends the ping opcode 0x9 at any time to ask the other side to pong back (the opcode 0xA).

The Web browser can ping the server when required, but a pong may sent at server’s discretion. If the endpoint receives a ping frame before responding the the previous one, the endpoint can elect to send just one pong frame for the most recently processed ping. The ping frame may contain the application data (can be up to 125 bytes) and pong must have identical data in its message body.

There is no JavaScript API to send pings or receive pong frames. Pings and pongs may or may not be supported by the user’s browser. There is also no API to enable, configure or detect whether the browser supports pings and pongs.

Data Frames

Since the WebSockets protocol allows the data to be fragmented into multiple frames, the first frame that transmits the data will be prepended with one of the following opcodes indicating the type of data being transmitted:

  • The opcode 0x01 indicates the UTF-8 encoded text data.

  • The opcode 0x02 indicates the binary data.

When your application transmits JSON over the wire the opcode is set to be 0x01. When your code emits binary data it will be represented in a browser specific Blob object or an ArrayBuffer object and sent wrapped into a frame with the opcode 0x02.

Note You must choose the type for the incoming binary data on the client using webSocket.binaryType = "blob" or webSocket.binaryType = "arraybuffer" before reading the data. It’s a good idea to check the type of the incoming data because the opcodes are not exposed to the client.
webSocket.onmessage = function(messageEvent) {
    if (typeof messageEvent.data === "string"){
        console.log("received text data from the server: " + messageEvent.data);
    } else if (messageEvent.data instanceof Blob){
        console.log("Blob data received")
    }
};
Closing The Connection

The connection is terminated by sending the frame with the close opcode 0x08.

There is the pattern to exchange close opcodes first and then let the server to shut down. The client is supposed to give the server some time to close the connection before attempting to do that on its own. The close event can also signal why it has terminated the connection.

A CloseEvent is sent to clients using WebSockets when the connection is closed. This is delivered to the listener indicated by the WebSocket object’s onclose handler. CloseEvent has 3 properties - code, reason, wasClean.

Table 2. Legend

code

This property represents the close code provided by the server.

reason

A string indicating the reason of why the server closed the connection.

wasClean

The property indicates if the connection was cleanly closed.

webSocket.onclose = function(closeEvent) {
    console.log("reason " + closeEvent.reason + "code " + closeEvent.code);
};

WebSocket frameworks

Working with the vanilla WebSocket API requires you to do some additional "housekeeping" coding on you own. For example, if the client’s browser doesn’t support WebSockets natively, you need to make sure that your code falls back to the legacy HTTP protocol. The good news is that there are frameworks that can help you with this task. Such frameworks lower the development time, allowing you to do more with less code. We’ve included brief reviews of two frameworks that can streamline your Web application development with WebSockets.

The frameworks mentioned below try to utilize the best supported transport by the current Web browser and server while sparing the developer from knowing internals of the used mechanism. The developer can concentrate on programming the application logic making calls to frameworks API when the data transfer is needed. The rest will be done by framework.

The Portal

The Portal is a server agnostic JavaScript library. It aims to utilize a WebSocket protocol and provides a unified API for various transports (long polling, HTTP streaming, WebSocket). Currently, once you’ve decided to use WebSocket API for your next project, you need to remember about those users who still use old browsers like Internet Explorer 9 or older, which don’t natively support WebSockets. In this case, your application should gracefully fall back to the best available networking alternative. Manually writing code to support all possible browsers and versions requires lots of time especially for testing and maintaining the code for different platforms. The Portal library could help as illustrated in the following brief code sample.

Simple asynchronous web application client with Portal
portal.defaults.transports = ["ws", "sse", "stream", "longpoll"];    // 1

portal.open("child-auction/auction").on({       // 2
    connecting: function() {
        console.log("The connection has been tried by '" + this.data("transport") + "'");
    },
    open: function() {                          // 3
        console.log("The connection has been opened");
    },
    close: function(reason) {
        console.log("The connection has been closed due to '" + reason + "'");
    },
    message: function(data) {
        handleIncommingData(data);
    },
    waiting: function(delay, attempts) {
        console.log("The socket will try to reconnect after " + delay + " ms");
        console.log("The total number of reconnection attempts is " + attempts);
    }
});
1 The Portal framework supports different transports and can fall back from WebSocket connection to streaming or long polling. The server also has to support some fall-back strategy, but no additional code required on the client side.
2 Connecting to the WebSocket endpoint.
3 The Portal API is event-based similarly to W3C WebSocket API.

The Portal framework generalizes the client-side programming. With defining an array of transports, you don’t have to worry about how to handle message sent by server with different transport. The Portal doesn’t depend on any JavaScript library.

Atmosphere

A Web application that has to be deployed on several different servers (e.g. WebSphere, JBoss, WebLogic) may need to support different WebSocket APIs. At the time of this writing, there is a plethora of different implementations of the server-side libraries supporting WebSockets, and each of them uses their own proprietary APIs. The upcoming Java EE 7 specification intends to change the situation. But Atmosphere is a framework that allows you to write portable Web applications today.

Atmosphere is a portable WebSocket framework supporting Java, Groovy, and Scala. The Atmosphere Framework contains both client and server components for building Asynchronous Web Applications. The Atmosphere transparently supports WebSockets, Server Side Events, long-polling, HTTP streaming, and JSONP.

The client side component Atmosphere.js simplifies the development of Web applications that require a fall back from the WebSocket protocol to long polling or HTTP streaming. The Atmosphere Framework hides the complexity of the asynchronous APIs, which differ from server to server and makes your application portable among them. Treat Atmosphere as a compatibility layer that allows to select best available on server transport for all major Java application servers.

The Atmosphere framework supports wide range of Java based server-side technologies via a set of extensions and plugins. The Atmosphere supports upcoming Java API for WebSocket, so you can have best of two worlds - the standard API and application portability.

Note WebSockets can be used not only in for the Web, but in any applications that use networking. If you’re developing native iOS or OSX applications check the SocketRocket library developed by Square Engineering Team.

Square uses SocketRocket in their mobile payments application. If you’re developing native Android applications and want to use WebSocket protocol goodies in Android-powered devices check the AsyncHttpClient framework.

When Using WebSockets

Since WebSocket protocol has literally no overhead it should be considered for the following types of applications:

  • Live trading/auctions/sports notifications

  • Controlling medical equipment over the web

  • Chat applications

  • Multi-player online games

  • Real-time updates in social streams

For the next version of Save Sick Child application we’re going to use WebSockets to implement an online auction communication layer. The goal is to let individuals and businesses purchase hand-made crafts and arts made by children. All proceeds will go to help sick children.

Having said that WebSocket protocol is a great solution, it has the downside too: the WebSockets specification defines only the protocol for transporting frames, but it doesn’t include the application-level protocol. Developers need to invent the application-specific text or binary protocols. For example, the auction bid has to be presented in a form agreed upon by all application modules. Let’s discuss our options from protocol modeling perspective.

Selecting a message format for your application’s data communications is important. The most common text formats are CSV, XML, and JSON. They are easy to generate, parse, and are widely supported by many frameworks in the most development platforms. While XML and JSON allow you to represent the data in a hierarchical and easily readable by humans form, they create a lot of overhead by wrapping up each data element into additional text identifiers. Sending such additional textual information requires extra bandwidth and may need additional string-to-type conversion on both the client and server’s application code. The binary format is an alternative way of sending data. Let’s discuss the pros and cons of these message formats.

CSV

CSV stands for Comma Separated Values although the delimiter can be any character, not only the comma. This depends on the parser design and implementation. Another popular type of delimiter is | - "pipe" .

Pros:

  • This format is very compact. The overhead of the separator symbol is minimal.

  • It’s simple to create and parse. The CSV message can be turned into array of values by using the standard JavaScript String.split().

Cons:

  • It’s not suitable for storing complex data structures and hierarchies. In case of an auction application, we need transfer to client auction items' attributes for each auction. In this case we can’t simply use String.split() and have to design and implement more complex parser.

XML

XML stands for Extensible Markup Language, and it nicely represents any hierarchal data structures.

Pros:

  • It’s a human-readable format.

  • Most browsers have build-in XML readers and parsers.

  • XML data can be validated against XSD or DTD schema.

    XML schema is very useful language feature as it defines the structure, content and semantic of XML document. Because of its human-readability the XML schema can be used used by people who are not software developers and can be applied for integrating systems written in different programming languages.

Cons:

  • XML is very verbose. To send a name of a customer you’d need something like this: <cust_name>Mary</cust_name>

  • The XML validation on the client is a complex task. As for now, there is no platform independent solutions or the API to perform validation programmatically based on XSD or DTD.

The book XML in a Nutshell, 3rd Edition by Elliotte Rusty Harold and W. Scott Means is a well-written book describing the full spectrum of XML features and tools.

JSON

As explained in Chapter 4, JSON stands for JavaScript Object Notation, and it’s a way of representing structured data, which can be encoded and decoded by all Web browsers. JSON is widely accepted by the Web community as a popular way of the data serialization.

Google Protocol Buffers

Google Protocol Buffers is a language and platform-neutral extensible mechanism for structured data serialization. Once defined how you want your data to be structured, you can use special generated source code to easily write and read your structured data to and from a variety of data streams.

A developer needs to specify how the serializable information has to be structured by defining the protocol buffer message types in the .proto files. Each protocol buffer message is a small logical record of information, containing a series of the name/value pairs. This protocol buffer message file is language agnostic. The protoc utility compiles proto files and produces language specific artifacts, e.g. .java, .js, etc files.

For example, you can create a protocol buffer proto file for our Save Sick Child to represent the information about donors.

Protocol Buffer for Donation message ( donation.proto )
package savesickchild;                                      // 1

option java_package = "org.savesickchild.web.donation";     // 2

message Donor{                                              // 3
    required string fullname = 1;
    required string email = 2;                              // 4
    required string address = 3;
    required string city = 4;
    required string state = 5;
    required int32 zip = 6;
    required string country = 7;

    message Donation{                                       // 5
        required Donor donor = 1;                           // 6
        required double amount = 2;
        optional bool receipt_needed = 3;
    }
}
1 The protobuf supports packages to prevent naming conflicts among messages from different projects.
2 Here we’re using Java specific protobuf option to define in what package the generated code will reside.
3 Start defining our custom message with the message keyword.
4 Each message field can be required, optional or repeated. The required and optional modifiers are self explanatory. During serialization-deserization process the protobuf framework will check the message for existence of fields, and if a required property is missing it will throw a runtime exception. The repeated modifier is used to create dynamically sized arrays.
5 The protobuf supports nested messages.
6 There are many standard field types available in protobuf: string, int32, float, double, and bool. You can also define a custom type and use it as a field type.

After creating the donation.proto file, you can use protoc compiler to generate Java classes according to this file’s definitions.

protoc -I=. --java_out=src donation.proto           # 1

.
├── donation.proto
└── src
    └── org
        └── savesickchild
            └── web
                └── donation
                    └── Donation.java               # 2
1 The Java code will be generated in src directory.
2 All required code for serialization-deserilization of Donation message will be included in Donation.java. We’re not going to publish the generated code here, but you can generate this code by yourself from the provided above message declaration.

Check the availability of the protobuf compiler for your preferred language at the protobuf wiki page. To make yourself familiar with protobuf technology check documentation and tutorials. Here some protobuf pros and cons protobuf:

Pros:

  • The message is encoded into a compact and optimized binary format. You can find the details of the encoding format at Protocol Buffers documentation website.

  • Google supports Protocol Buffers for a wide range of programming languages (Java, C++, Python). The developer’s community supports it too.

  • The use of Protocol Buffers is well documented.

Cons:

  • The binary format is not human readable.

  • Although Protobuf is compact, especially when a lot of numeric values are transferred by an encoding algorithm, the JSON is natively supported by the JavaScript and doesn’t require any additional parser implementation.

  • Protobuf requires the Web browser to support the binary format, but not all of them do it just yet. You can find which browser support raw binary data at http://caniuse.com/#search=binary.

WebSockets and Proxies

The WebSocket protocol itself is unaware of intermediaries such as proxy servers, firewalls, content filters. The proxy servers are commonly used for content caching, security and enterprise content filtering.

HTTP always supported protocol upgrades, but many proxy servers seem to have ignored that part of the specification. Until the WebSockets came around the Upgrade attribute was not used. The problem with Web applications that use long-lived connection like WebSocket is that the proxy servers may choose to close streaming or idle WebSocket connections, because they appear to be trying to connect to the unresponsive HTTP server. Additionally, proxy servers may buffer unencrypted HTTP responses assuming that the browser needs to receive the HTTP response in its entirety.

If you want to get more details on how a WebSockets-enabled application has to deal with proxies there is comprehensive research paper by Google’s Peter Lubbers WebSocket and proxy servers.

Adding an Auction to Save Sick Child

We gave you just enough of a theory to whet your appetite for implementing WebSockets in our Save Sick Child application. The goal is to create an auction where people can bid and purchase various goods so the proceeds would go to sick children. Auctions require real-time communications - everyone interested in the particular auction item must be immediately notified if another bidder increased the price. So we’ll use WebSockets as a means for bidding and notifications of the changes in the auction.

To start the auction, the user of the Save Sick Child application has to select the Auction option under the menu Way To Give. We realize that only a small number of the users will decide to participate in the auction, which from the architectural point of view means that the code supporting the auction should be loaded on demand only if the user chooses to visit the auction. This why we need to write this code as a loadable module, and the reader will get a practical example of how a Web application can be modularized.

In this chapter we continue to use RequireJS explained in the previous chapter as a framework that helps manage our JavaScript application components in a modular fashion. Using RequireJS, we’re going to lazy load some modules if and only if they ever get requested by the user.

This is dedicated to the development of the user interface and client side of the Web applications hence we’re not going to cover all the details of server side implementation, but will make our server side code available for download. We’ll keep our server up and running so you can test the UI, but our main goal in this section is to show you how you can exchange the auction data with the server and process them on the client side. We use the current version of WebSockets support offered by the Java application server GlassFish 4, which is a reference implementation of the latest Java EE 7 specification.

Authors of this book are Java developers and we have provided a sidebar with the details WebSockets server API which is a part of Java EE 7. If you are not a Java developer, you may want to learn on your own which WebSocket servers exist for your favorite programming language or platform. But strictly speaking, if you are a front-end developer, you don’t have to know how the WebSocket server works under the hood.

WebSockets Server with Java EE 7 and Java API for WebSocket.

If you interesting how to setup and run please watch followed screencast at http://youtube.com/trainingAtFarata

In Chapter 8 you had a chance to see how a Web application can be sliced (see Aptana’s project-15-dynamic-modules) into several modules using Require.js framework. We’ll take this project as a base and will create a new one: project16-websocket-auction adding to it the new modules supporting the auction.

Way To Give module (js/modules/way-to-give.js)
define([], function () {
    var WayToGiveMod = function () {
        return {
            renderControls: function () { // 1

            },
            startAuction: function () {   // 2
            },
            rendered: false             // 3
        }
    };
    return WayToGiveMod;
});
1 This function will lazy load the auction application content and render it to the top main section of the Web page.
2 This function will start the auction.
3 The module stores the rendering state in this property.

Once the application starts, the require.js loads only essential modules - login and donation [FIG9-9].

images/fig_09_09.png
Figure 52. Two modules are loaded during the Save Sick Child application startup

In Google Chrome Developer Tools Console we can see that login and donation modules are reporting about successful loading. In [FIG9-10] we can see that these modules perform fine.

images/fig_09_10.png
Figure 53. Two modules are loaded during the Save Sick Child application startup

Now click WayToGive menu item and keep an eye on the Developer Tools Console [FIG9-11]. You will see how the WayToGive module reports about its loading and rendering.

images/fig_09_11.png
Figure 54. The auction controls are loaded and rendered

Once the user clicks the menu Way to Give the framework require.js has to load code of WebSocket-based auction module. Here is the code of app.js - the entry point of our Save Sick Child application. The following code snipped illustrates the mechanics how we loading the module on demand.

require([], function() {    // 1
  return(function() {
    var lazyLoadingEventHandlerFactory, wayToGiveHandleClick, wayToGiveModule, way_to_give;
    way_to_give = document.getElementById("way-to-give");

    wayToGiveModule = null;     // 2

    lazyLoadingEventHandlerFactory = function(module, modulePath) {
      var clickEventHandler;
      clickEventHandler = function(event) {
        console.log(event.target);
        if(module === "loading") {    // 3
          return;
        }
        if(module !== null) {
          return module.startAuction();      // 4
        } else {
          module = "loading";                // 5
          return require([modulePath], function(moduleObject) { // 6
            module = new moduleObject();
            return module.render();                             // 7
          });
        }
      };
      return clickEventHandler;
    };
    wayToGiveHandleClick = lazyLoadingEventHandlerFactory(wayToGiveModule, "modules/way-to-give");

    way_to_give.addEventListener("click", wayToGiveHandleClick, false);   // 8
  })();
});
1 This function will lazy-loaded only if the user clicks on Way To Give menu.
2 WayToGive module will has a value if null until loaded.
3 If the user clicks while the WayToGive module is still being lazily loaded, simply ignore this click - when the module finally loads, it will open the module.
4 If the module has been loaded and UI has been rendered start Auction application.
5 Set an intermediary value to the WayToGive module so that subsequent requests don’t try to launch the module more than once.
6 Load module asynchronously and instantiate it.
7 Render UI component to the screen for first time.
8 Register the click event listener for the Way To Give menu.

After the UI elements have rendered we can connect to the WebSocket server and request list of all available auction items.

 if(window.WebSocket) {
   webSocket = new WebSocket("ws://localhost:8080/child-auction/auction");
   webSocket.onopen = function() {
     console.log("connection open...");         //1
     getAuctionsList();
   };
   webSocket.onclose = function(closeEvent) {
     console.log("close code " + closeEvent.code);
   };
   webSocket.onmessage = function(messageEvent) {
     console.log("data from server: " + messageEvent.data);
     if(typeof messageEvent.data === "string") {
       handleMessage(messageEvent.data);
     }
   };
   return webSocket.onerror = function() {
     console.log("websocket error");
   };
 }
1 After establishing connection we’re requesting list of available auctions. We’ll see details of getAuctionsList() method in next snipped.
var getAuctionsList = function() {
        var auctionListMessage = new AuctionMessage("AUCTIONS_LIST", 'gime', "-1"); // 1
        if(webSocket.readyState === 1) {        // 2
            webSocket.send(auctionMessage.toJson());
        } else {
            return console.log("offline");
        }
    };
1 Forming the request message. Details of the message format could be found in [Auction_Messages_Specification] section.
2 Checking the WebSocket object state. If WebSocket is open (readyState===1) the application can send a message. If not, just simply log this on the console. In the real world situations if your users work on unstable networks such as cellular or 3G you definitely don’t want to lose any bits of your data. It’s a good idea to use local storage API to persist the data locally until application gets back online and resubmit the data.

The user can select a lot from combo box and see photos of it [FIG9-12] and [FIG9-13]

images/fig_09_12.png
Figure 55. The console logs incoming message contains list of auction items.
images/fig_09_13.png
Figure 56. Using Network feature of Dev Tools we can monitor WebSocket frames.
images/fig_09_14.png

Monitor the WebSockets traffic with Chrome Developers Tools

Let’s see whatever is described in the [HANDSHAKE] action. With the help of Chrome Developer Tools you can monitor the information about the initial handshake [FIG9-4]. This can be viewed in the Network tab after selecting the path of the WebSocket endpoint.

images/fig_09_04.png
Figure 57. Initial WebSockets handshake in Chrome DevTools

You can also click on WebSockets on the bottom-right to show only the WebSocket endpoints. Click on Frames in the right panel to view the actual frames being exchanged between the client and server. [FIG9-5]. The white colored rows represent incoming data, and the green rows - outgoing.

images/fig_09_05.png
Figure 58. Monitoring WebSocket frames in Chrome Developer Tools

For more gore details you can navigate your Google Chrome to the secret URL - chrome://net-internals, which is a very useful URL showing a lot of additional information (see [FIG9-6] and [FIG9-7] ).

images/fig_09_06.png
Figure 59. Details of initial handshake in Chrome Net Internals
images/fig_09_07.png
Figure 60. Details of the socket connection

Google Developer Tools show just the length of payload data. But chrome://net-internals shows the actual size of the WebSocket frame too. [FIG9-8] compares the views of net-internals and Developer Tools. As we learned earlier in this chapter, the total size of frame is slightly different from size of the payload. There are few bytes for frame header. Moreover, all outgoing messages will be masked by the browser(see NOTE in [FRAMES] section). This frame’s mask is going to be transferred to the server as a part of the frame itself, which creates additional 32 bits = 4 bytes overhead.

images/fig_09_08.png
Figure 61. Dev tools and net-internals side by side

Sniffing WebSockets frames with Wireshark

Wireshark is a powerful and comprehensive monitoring tool for analyzing the network traffic.You can download it from their web site. To start capturing the WebSocket traffic you need to select the network interface from list and click "Start" [FIG9-15]. In our case we’re going to select the loopback interface to capture traffic on localhost.

images/fig_09_15.png
Figure 62. Wireshark application main view

Wireshark is going to capture all network activity. Set up the filter to see only the data you are interested in. We want to capture HTTP traffic and TCP traffic on port 8080 because our WebSocket server (Oracle’s GlassFish) runs on this port [FIG9-16]. Enter http && (tcp.dstport==8080) in the filter text box and click Apply.

images/fig_09_16.png
Figure 63. Filter setup

Now Wireshark is ready to sniff at the traffic of our application. You can start the auction session and place bids. After you’re done with the auction you can return to Wireshark window and analyze what we got. You can see initial handshake (GET request [FIG9-17] and Upgrade response [FIG9-18])

images/fig_09_17.png
Figure 64. The GET request for protocol upgrade
images/fig_09_18.png
Figure 65. The GET response with protocol upgrade

After the successful connection upgrade, Wireshark captured http-alt stream on 8080 port. This is our WebSocket connection. Right click on this row and select Follow TCP Stream [FIG9-19].

images/fig_09_19.png
Figure 66. The GET response with protocol upgrade

On the next screen you can see the details of WebSocket frame [FIG9-20]. We took this screenshot right after the auction application started. You can see here the data with list of available auctions. The outgoing data marked with red color and the incoming data marked with blue color.

images/fig_09_20.png
Figure 67. WebSocket frame

We took next screenshot [FIG9-21] after the action has been finished. We can see here entire data that were sent over WebSocket connection.

images/fig_09_21.png
Figure 68. Entire auction conversation

Auction Messages Specification

  1. The client’s code connects to the WebSockets endpoint on the server.

  2. The client’s code sends AUCTION_LIST message to retrieve the list of currently running auctions.

    Request for list of available auctions
    {
        "type": "AUCTIONS_LIST", // 1
        "data": "empty",        // 2
        "auctionId": "-1"       // 3
    }
    1 type of message is AUCTION_LIST
    2 empty data
    3 We don’t know exact auction id so we just send -1

    Let’s review the JSON object that will be arriving from the server as the auction’s response.

    Response with auction list data
    {
        "type": "AUCTIONS_LIST",    // 1
        "data": [                   // 2
            {
                "auctionState": "AUCTION_NOT_RUNNING",
                "item": {           // 3
                    "name": "Painting",
                    "description": "Fancy",
                    "startingPrice": 1000.0,
                    "auctionStartTime": 6000,
                    "bidTimeoutS": 30
                },
                "bestBid": 1000.0,
                "participantList": [],
                "auctionId": "first" // 4
            },
            {
                "auctionState": "AUCTION_RUNNING",
                "item": {
                    "name": "Handmade hat",
                    "description": "Awesome",
                    "startingPrice": 2000.0,
                    "auctionStartTime": 6000,
                    "bidTimeoutS": 30
                },
                "bestBid": 2000.0,
                "participantList": [],
                "auctionId": "second"
            }
        ],
        "auctionId": "0"
    }
    1 The message type is AUCTION_LIST
    2 The data property of the response object contains the list of all running auctions. An auction can be in one of three states: not running, running, or finished.
    3 The item property of the response object is a nested object that represents the auction item.
    4 The auctionId property contains a unique identifier of the selected auction.
  3. The user picks the auction from the list, enters a desired nick name, and joins to the auction. The client-side application sends the following login message.

    {
        "type": "LOGIN", // 1
        "data": "gamussa", // 2
        "auctionId": "second" //3
    }
    1 The message type is LOGIN
    2 The data property of the request contains the user’s nickname.
    3 The auctionId property helps the server-side code to route the message to the correct auction.
    Note As soon as the handshake completes successfully, the server side code that implements WebSocket protocol exposes the WebSocket session object. The session object encapsulates conversation between the WebSocket endpoint (server - side) and remote endpoint (browser). Check the documentation for your server side framework for details about how it handles and exposes the remote endpoints in API.
  4. Each time when the user enters the bid price client side code sends following bid message:

    Bit message
    {
        "type": "BID",
        "data": "1100.0",
        "auctionId": "second"
    }

    This is outgoing message. When user clicks on "Bid!" button text from bid text box wrapped to Bid message. On the server, bid message data value compared with best bid value and if it’s

  5. PriceUpdate message

    PriceUpdate message
    {
        "type": "PRICE_UPDATE", //1
        "data": "1300.0", //2
        "auctionId": "second"
    }
    1 If some auction participant outbids others, the rest of participants will receive update.
    2 Such an update will contain the current highest bid.
  6. AuctionResult message

    AuctionResult message
    {
        "type": "RESULT",
        "data": "Congrats! You\u0027ve won Painting for $1300.0",
        "auctionId": "first"
    }

    After the auction ends, the server broadcasts the message with auction results. If the wining user is online and connected to the auction server, the item message will contain congratulations. Other participant will get the loose notifications.

Summary

This chapter was about the WebSocket protocol. By now you should see the benefits of using WebSocket protocol in applications. In many cases WebSockets is an ultimate means for improving the application performance by reducing the network latency and removing the HTTP-headers overhead. We learned how to integrate WebSocket-based functionality into the existing HTTP-based application Save Sick Child.

You’ve learned how to use the network monitoring capabilities of Google Chrome Developer Tools and Wireshark application by sniffing the WebSocket traffic. You can’t underestimate the importance of monitoring tools, which are the best friends of Web developers.

Part 2: Mobile

Chapter 11. Responsive Design: One Site Fits All

Up till now we’ve been writing and re-writing the desktop version of the Save Sick Child application. Will it look good on the small screen of a mobile device?

Let’s discuss different approaches to making the Web site for mobile devices. One of the approaches is having only one Web site for all devices. There are three choices:

  1. Develop separate version of native applications for each mobile device. Developing of native mobile applications is not covered in this book.

  2. Develop one HTML5 Web application, but create several different UI layouts that will be applied automatically based on the screen size of the user’s device.

  3. Develop a hybrid application, which is a Web application on steroids - it can invoke native API of the mobile device. Chapter 14 is dedicated to hybrid applications.

The chapter is about the second approach called Responsive Design, and we’ll modify the design of the Save Sick Child site to introduce different layouts for the desktop, tablet, and smart phones. By the end of this chapter the site Save Sick Child will automatically change its layout based on the user’s device without the losing functionality.

One Code Base vs. Two

Run any of the versions of our Save Sick Child applications on your desktop and start dragging the right border of the browser’s window to make it narrower. At some point you’ll see only a part of the content - the layout of Save Sick Child is not responsive just yet. It defines fixed sizes for the page sections, which don’t change event if the display area shrinks.

Or enter the address of one of the Save Sick Child projects in your mobile phone’s browser. Either you’ll see a partial content of the page or the entire page with illegible small fonts. At this point the only design of the Save Sick Child application doesn’t look good on all devices.

How many versions of the UI do we need to create then? People responsible for developing a Web application that can run on both desktop and mobile platforms usually start with making an important decision: HTML5 or native? But even if a decision was made in the favor of the Web platform, the next question is if the desktop and mobile clients will use the same code or not.

If a decision is made to go with separate versions of the Web applications, the Web server can be configured to perform the redirection to the appropriate code depending on the type of the user’s device. Web servers can do it based on the value of the User-Agent attribute of the HTTP request header. For example, the mobile Web browsers trying to access of BBC (or any other Web page) report their User-Agent to the server differently from desktop computers hence they recive different content delivered from a different URL. The snapshots [FIG11-1] and [FIG11-2] of the BBC main page were taken at the same time, but [FIG11-1] shows how the page looks on the desktop computer, while [FIG11-2] was taken from the iPhone.

images/fig_11_01.jpg
Figure 69. The desktop version of bbc.com

The [FIG11-1] page layout delivers more content that can be allocated nicely on the large desktop monitor or a tablet. But the mobile version on [FIG11-2] substantially limits what’s delivered to the client, which is done not only because the screen is small, but the user may be accessing the page over the slower network.

images/fig_11_02.png
Figure 70. The mobile version of bbc.com

Have you ever tried to share the link of the Web site from your iPhone? It’s so easy! Just press the button and enter the email of the person to share the site with. Go to bbc.com from your iPhone or Android phone and share this link with someone. That person will receive the link http://www.bbc.co.uk/mobile/i, and if she’s visit this site from the desktop it won’t look pretty. It’ll just show the wider version of what you see in [FIG11-2]. Try to enter this URL in your desktop browser to see for yourself.

Maintaining two different versions of the application code requires more efforts than maintaining one: you need to have two sets of HTML, CSS, JavaScript, and images. Besides, most likely your Web application will use a third-party JavaScript framework. At some point you may run into a bug and will need to upgrade the mobile version to use the latest version of, say jQuery framework. But the desktop version works just fine. In case of having two separate versions of the application you’ll have to either upgrade jQuery and thoroughly test both mobile and desktop versions of Save Sick Child, or live with two different versions of the framework.

Responsive design allows you to create one version of the Web application, which includes multiple sections of CSS controlling page layouts for different screen sizes. In this chapter we’ll create yet another version of the Save Sick Child application that will render UI differently on desktop and mobile devices. All these version will share the same HTML and JavaScript code, but will include several versions of styling using CSS media queries.

There is a number of Web sites that were built using responsive design. Visit the following Web sites first from the desktop computer and then from smart phones (or just lower the width of the desktop browser window) to experience such fluid responsive design:

Note that each of these Web pages displays the content on the desktop in three different layouts (often in three imaginary columns). As you make the window narrower, the layout will automatically switch to the tablet mode (usually two columns layout), and then to the smart phone mode layout (the one column layout).

This sounds like a great solution, but keep in mind that your users will be downloading unnecessary bytes - the entire CSS file that includes all versions of screen layouts. This is not the case in the BBC example, which has different versions of the code that load only what’s necessary for a particular device category.

Now comes the million dollar question, "Do we need to create two different versions of the Web application or twenty two? Why not two hundred and twenty two?" How many different mobile devices are there today and will be there tomorrow?

How many User Agents are there

The HTTP header’s attribute User-Agent contains information about the user agent originating request. Should you decide to create several versions of the UI based on the value in the User-Agent field, you can refer to the Web site http://useragentstring.com. It lists not two, but hundreds of strings representing possible content of the User-Agent attribute for a variety of desktop and mobile devices. For example, [FIG11-3] shows how the User-Agent string from iPhone5 is reported and explained by useragentstring.com.

images/fig_11_03.png
Figure 71. The User-Agent String from iPhone 5

It’s impossible to create different layouts of a Web application for thousands of user agents. Grouping devices by screen sizes is a more practical approach for lowering the number of required UI layouts. This is where CSS media queries come handy.

CSS Media Queries

Media Queries is a W3C Recommendation that has been implemented in CSS2 and HTML4. The idea is to provide different stylesheet for different media. For example, you can specify different stylesheets in HTML for the screen and for printing:

<link rel="stylesheet" href="assets/css/style.css" media="screen">

<link rel="stylesheet" href="assets/css/style_pr.css" media="print">

In CSS a CSS file

Tip Dreamweaver CS6 automates creation of media queries

Chapter 14. Hybrid Applications: HTML + Native API

Both Web and native applications have their pros and cons. Let’s start with some of the examples of the native applications that exist today.

Bank of America’s native mobile application allows you to deposit checks by taking a photo of the front and back sides of the check and entering the amount. At the time of this writing, they support iPhones, Android, Windows phones, and iPads.

Near Field Communication (NFC) technology allows NFC-enabled devices communicate with each other in close distance using radio frequencies. NFC can be used for payments (no need to enter passwords) and data sharing (contacts, photos, et al.). Proliferation of NFC in banking will seriously hurt the credit cards industry. A number of smartphones already support NFC technology (see http://www.nfcworld.com/nfc-phones-list). Add one of the existing fingerprint biometrics solutions, and your mobile phone becomes your wallet.

While native applications have full access to all hardware of the device (e.g. camera, microphone, et al.), they have drawbacks too. For instance, if you want to publish your application at Apple’s App Store you have to submit your application in advance and wait for an approval. If a crucial bug is found in your application, even though if you could fix it in a day, you can’t put a new version in production until it went through an approval process. Back in 2011 Financial Times (FT) decided to stop using their native iOS application because Apple wouldn’t share the data about FT subscribers. Don’t forget that Apple would get their own cut from each FT subscription.

On one hand it’s good to have an ability to publish your latest Web applications on your own servers without the need to ask for a permission. On the other hand, the presence on Apple’s iTunes is a good channel for bringing new customers. The publisher of New York magazine is heavily investing into their native application for iPad but the newer versions of their Web applications are as engaging as their native piers. If you Web application has to be discoverable and visible by search engines, Web application are definitely better.

The hybrid applications promise you to have the best of both worlds. A Web application written in HTML/JavaScript has access to the hardware of the mobile device via a third-party library such as PhoneGap.The PhoneGap recompiles HTML/JavaScript code to create a platform specific application with an embedded Web browser, where your HTML/JavaScript code will run. This embedded browser (a.k.a. Web View) is chrome-less and your application is getting access to full size of the device screen.

The PhoneGap packaging tool takes your HTML/JavaScript/CSS code, compiles it for the required mobile platform and create a native application that has access to the native functionality of hardware, for example, if you need to deploy it under iOS, you’ll get an IPA file, and for deployment on Android devices you’d be getting an APK file. The hybrid applications may be not as fast as the native ones, and the architects responsible for defining mobile enterprise strategy must setting their priorities.

If a particular application will be used only by the employees of the organization who will use limited and defined number of mobile devices, and if making employees productive is the main goal - develop native applications. Start with developing and deploying such an application for the pilot OS (typically iOS 6 or Android 4), and then gradually add support for more  platforms, budget permitting. If you are planning to develop a Web application with relatively simple UI (e.g. Save Sick Child) and have to support a wide variety of unknown consumer devices (e.g. allow people make donation from any device) - develop a HTML5 Web application.

Consider developing a hybrid application for anything in between, and in this chapter we’ll create a hybrid version of our Save Sick Child application with PhoneGap framework. To be more specific, we’ll access the location services of the smartphone and will use the PhoneGap PayPal plugin to process donations.

Tip For current list of available PhoneGap plugins for various mobile platforms visit the github repository at https://github.com/phonegap/phonegap-plugins.

What’s PhoneGap

First of all, PhoneGap is not a competitor of such JavaScript frameworks as jQuery, Ext JS, AngularJS, Ember.js and the like. PhoneGap is a technology for creating an application container can run code written with or without using these frameworks, and its main goal is to provide the JavaScript API for getting access to the hardware of mobile devices as well as the build tool for its subscribers.

Note PhoneGap is a brand own by Adobe. Apache Foundation has an open source project called Cordova, which started from the code donated by Adobe to Apache. Lots of developers from around the world work on Cordova, but Adobe’s using this library to create their own way of compiling and distributing mobile applications, which is branded as PhoneGap. The closest analogy is the Chrome and Safari browsers built on the same open source rendering engine Webkit.